|
@@ -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);
|
|
|
+ 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 false;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- if (backupFile != null) {
|
|
|
- try {
|
|
|
- Files.copy(backupFile, pathToConfig, StandardCopyOption.REPLACE_EXISTING);
|
|
|
- return LOCKED;
|
|
|
- } catch (IOException e) {
|
|
|
- return vaultState;
|
|
|
- }
|
|
|
- } else {
|
|
|
- return vaultState;
|
|
|
- }
|
|
|
+ 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 vaultState;
|
|
|
+ return false;
|
|
|
}
|
|
|
}
|
|
|
|