mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-04-17 08:06:52 -04:00
improve RecoverUtil and determineVaultState
This commit is contained in:
@@ -11,10 +11,8 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.cryptomator.common.vaults.VaultState.Value.LOCKED;
|
||||
import static org.cryptomator.cryptofs.common.Constants.DATA_DIR_NAME;
|
||||
import static org.cryptomator.cryptolib.api.CryptorProvider.Scheme.SIV_CTRMAC;
|
||||
import static org.cryptomator.cryptolib.api.CryptorProvider.Scheme.SIV_GCM;
|
||||
@@ -22,64 +20,61 @@ import static org.cryptomator.cryptolib.api.CryptorProvider.Scheme.SIV_GCM;
|
||||
public class RecoverUtil {
|
||||
|
||||
public static CryptorProvider.Scheme detectCipherCombo(byte[] masterkey, Path pathToVault) {
|
||||
try {
|
||||
Path dDirPath = pathToVault.resolve(DATA_DIR_NAME);
|
||||
|
||||
Optional<Path> firstC9rFile;
|
||||
try (Stream<Path> paths = Files.walk(dDirPath)) {
|
||||
firstC9rFile = paths.filter(path -> path.toString().endsWith(".c9r")).findFirst();
|
||||
}
|
||||
if (firstC9rFile.isEmpty()) {
|
||||
throw new IllegalStateException("No .c9r file found.");
|
||||
}
|
||||
|
||||
Path c9rFile = firstC9rFile.get();
|
||||
if (canDecryptFileHeader(c9rFile, new Masterkey(masterkey), SIV_GCM)) {
|
||||
return SIV_GCM;
|
||||
}
|
||||
if (canDecryptFileHeader(c9rFile, new Masterkey(masterkey), SIV_CTRMAC)) {
|
||||
return SIV_CTRMAC;
|
||||
}
|
||||
|
||||
return null;
|
||||
try (Stream<Path> paths = Files.walk(pathToVault.resolve(DATA_DIR_NAME))) {
|
||||
return paths.filter(path -> path.toString().endsWith(".c9r"))
|
||||
.findFirst()
|
||||
.map(c9rFile -> determineScheme(c9rFile, masterkey))
|
||||
.orElseThrow(() -> new IllegalStateException("No .c9r file found."));
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Failed to detect cipher combo.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean canDecryptFileHeader(Path c9rFile, Masterkey masterkey, CryptorProvider.Scheme scheme) {
|
||||
try (Cryptor cryptor = CryptorProvider.forScheme(scheme).provide(masterkey, SecureRandom.getInstanceStrong())) {
|
||||
private static CryptorProvider.Scheme determineScheme(Path c9rFile, byte[] masterkey) {
|
||||
try {
|
||||
ByteBuffer header = ByteBuffer.wrap(Files.readAllBytes(c9rFile));
|
||||
cryptor.fileHeaderCryptor().decryptHeader(header);
|
||||
return tryDecrypt(header, new Masterkey(masterkey), SIV_GCM) ? SIV_GCM :
|
||||
tryDecrypt(header, new Masterkey(masterkey), SIV_CTRMAC) ? SIV_CTRMAC : null;
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean tryDecrypt(ByteBuffer header, Masterkey masterkey, CryptorProvider.Scheme scheme) {
|
||||
try (Cryptor cryptor = CryptorProvider.forScheme(scheme).provide(masterkey, SecureRandom.getInstanceStrong())) {
|
||||
cryptor.fileHeaderCryptor().decryptHeader(header.duplicate());
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static VaultState.Value tryBackUpConfig(Path pathToConfig, VaultState.Value vaultState) {
|
||||
try (Stream<Path> files = Files.list(pathToConfig.getParent())) {
|
||||
Path backupFile = files.filter(file -> {
|
||||
String fileName = file.getFileName().toString();
|
||||
return switch (vaultState) {
|
||||
case VAULT_CONFIG_MISSING -> fileName.startsWith("vault.cryptomator") && fileName.endsWith(".bkup");
|
||||
case MASTERKEY_MISSING -> fileName.startsWith("masterkey.cryptomator") && fileName.endsWith(".bkup");
|
||||
default -> false;
|
||||
};
|
||||
}).findFirst().orElse(null);
|
||||
|
||||
if (backupFile != null) {
|
||||
try {
|
||||
Files.copy(backupFile, pathToConfig, StandardCopyOption.REPLACE_EXISTING);
|
||||
return LOCKED;
|
||||
} catch (IOException e) {
|
||||
return vaultState;
|
||||
}
|
||||
} else {
|
||||
return vaultState;
|
||||
}
|
||||
public static boolean restoreBackupIfAvailable(Path configPath, VaultState.Value vaultState) {
|
||||
try (Stream<Path> files = Files.list(configPath.getParent())) {
|
||||
return files
|
||||
.filter(file -> matchesBackupFile(file.getFileName().toString(), vaultState))
|
||||
.findFirst()
|
||||
.map(backupFile -> copyBackupFile(backupFile, configPath))
|
||||
.orElse(false);
|
||||
} catch (IOException e) {
|
||||
return vaultState;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean matchesBackupFile(String fileName, VaultState.Value vaultState) {
|
||||
return switch (vaultState) {
|
||||
case VAULT_CONFIG_MISSING -> fileName.startsWith("vault.cryptomator") && fileName.endsWith(".bkup");
|
||||
case MASTERKEY_MISSING -> fileName.startsWith("masterkey.cryptomator") && fileName.endsWith(".bkup");
|
||||
default -> false;
|
||||
};
|
||||
}
|
||||
|
||||
private static boolean copyBackupFile(Path backupFile, Path configPath) {
|
||||
try {
|
||||
Files.copy(backupFile, configPath, StandardCopyOption.REPLACE_EXISTING);
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -172,19 +172,33 @@ public class VaultListManager {
|
||||
}
|
||||
|
||||
private static VaultState.Value determineVaultState(Path pathToVault, VaultSettings vaultSettings) throws IOException {
|
||||
Path pathToVaultConfig = Path.of(pathToVault.toString(),"vault.cryptomator");
|
||||
Path pathToMasterkey = Path.of(pathToVault.toString(),"masterkey.cryptomator");
|
||||
Path pathToVaultConfig = pathToVault.resolve("vault.cryptomator");
|
||||
Path pathToMasterkey = pathToVault.resolve("masterkey.cryptomator");
|
||||
|
||||
if (!Files.exists(pathToVault)) {
|
||||
if (Files.notExists(pathToVault)) {
|
||||
return VaultState.Value.MISSING;
|
||||
}
|
||||
else if (Files.notExists(pathToVaultConfig)) {
|
||||
return RecoverUtil.tryBackUpConfig(pathToVaultConfig, VAULT_CONFIG_MISSING);
|
||||
|
||||
boolean vaultConfigRestored = Files.notExists(pathToVaultConfig) &&
|
||||
RecoverUtil.restoreBackupIfAvailable(pathToVaultConfig, VaultState.Value.VAULT_CONFIG_MISSING);
|
||||
|
||||
boolean masterkeyRestored = Files.notExists(pathToMasterkey) &&
|
||||
KeyLoadingStrategy.isMasterkeyFileVault(vaultSettings.lastKnownKeyLoader.get()) &&
|
||||
RecoverUtil.restoreBackupIfAvailable(pathToMasterkey, VaultState.Value.MASTERKEY_MISSING);
|
||||
|
||||
if (vaultConfigRestored || masterkeyRestored) {
|
||||
return LOCKED;
|
||||
}
|
||||
else if (Files.notExists(pathToMasterkey) &&
|
||||
|
||||
if (Files.notExists(pathToVaultConfig)) {
|
||||
return VaultState.Value.VAULT_CONFIG_MISSING;
|
||||
}
|
||||
|
||||
if (Files.notExists(pathToMasterkey) &&
|
||||
KeyLoadingStrategy.isMasterkeyFileVault(vaultSettings.lastKnownKeyLoader.get())) {
|
||||
return RecoverUtil.tryBackUpConfig(pathToMasterkey, MASTERKEY_MISSING);
|
||||
return VaultState.Value.MASTERKEY_MISSING;
|
||||
}
|
||||
|
||||
return checkDirStructure(pathToVault);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user