<commit_before>/*******************************************************************************
 * Copyright (c) 2017 Skymatic UG (haftungsbeschränkt).
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the accompanying LICENSE file.
 *******************************************************************************/
package org.cryptomator.cryptofs.migration;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Map;
import java.util.Optional;

import javax.inject.Inject;

import org.cryptomator.cryptofs.common.Constants;
import org.cryptomator.cryptofs.common.FileSystemCapabilityChecker;
import org.cryptomator.cryptofs.migration.api.MigrationProgressListener;
import org.cryptomator.cryptofs.migration.api.Migrator;
import org.cryptomator.cryptofs.migration.api.NoApplicableMigratorException;
import org.cryptomator.cryptolib.Cryptors;
import org.cryptomator.cryptolib.api.InvalidPassphraseException;
import org.cryptomator.cryptolib.api.KeyFile;
import org.cryptomator.cryptolib.api.UnsupportedVaultFormatException;

/**
 * Used to perform migration from an older vault format to a newer one.
 * <p>
 * Example Usage:
 * 
 * <pre>
 * <code>
 * if (Migrators.get().{@link #needsMigration(Path, String) needsMigration(pathToVault, masterkeyFileName)}) {
 * 	Migrators.get().{@link #migrate(Path, String, CharSequence, MigrationProgressListener) migrate(pathToVault, masterkeyFileName, passphrase, migrationProgressListener)};
 * }
 * </code>
 * </pre>
 * 
 * @since 1.4.0
 */
public class Migrators {

	private static final MigrationComponent COMPONENT = DaggerMigrationComponent.builder() //
			.migrationModule(new MigrationModule(Cryptors.version1(strongSecureRandom()))) //
			.build();

	private final Map<Migration, Migrator> migrators;
	private final FileSystemCapabilityChecker fsCapabilityChecker;

	@Inject
	Migrators(Map<Migration, Migrator> migrators, FileSystemCapabilityChecker fsCapabilityChecker) {
		this.migrators = migrators;
		this.fsCapabilityChecker = fsCapabilityChecker;
	}

	private static SecureRandom strongSecureRandom() {
		try {
			return SecureRandom.getInstanceStrong();
		} catch (NoSuchAlgorithmException e) {
			throw new IllegalStateException("A strong algorithm must exist in every Java platform.", e);
		}
	}

	public static Migrators get() {
		return COMPONENT.migrators();
	}

	/**
	 * Inspects the vault and checks if it is supported by this library.
	 * 
	 * @param pathToVault Path to the vault's root
	 * @param masterkeyFilename Name of the masterkey file located in the vault
	 * @return <code>true</code> if the vault at the given path is of an older format than supported by this library
	 * @throws IOException if an I/O error occurs parsing the masterkey file
	 */
	public boolean needsMigration(Path pathToVault, String masterkeyFilename) throws IOException {
		Path masterKeyPath = pathToVault.resolve(masterkeyFilename);
		byte[] keyFileContents = Files.readAllBytes(masterKeyPath);
		KeyFile keyFile = KeyFile.parse(keyFileContents);
		return keyFile.getVersion() < Constants.VAULT_VERSION;
	}

	/**
	 * Performs the actual migration. This task may take a while and this method will block.
	 * 
	 * @param pathToVault Path to the vault's root
	 * @param masterkeyFilename Name of the masterkey file located in the vault
	 * @param passphrase The passphrase needed to unlock the vault
	 * @throws NoApplicableMigratorException If the vault can not be migrated, because no migrator could be found
	 * @throws InvalidPassphraseException If the passphrase could not be used to unlock the vault
	 * @throws FileSystemCapabilityChecker.MissingCapabilityException If the underlying filesystem lacks features required to store a vault
	 * @throws IOException if an I/O error occurs migrating the vault
	 */
	public void migrate(Path pathToVault, String masterkeyFilename, CharSequence passphrase, MigrationProgressListener progressListener) throws NoApplicableMigratorException, InvalidPassphraseException, IOException {
		fsCapabilityChecker.assertAllCapabilities(pathToVault);
		<commit_msg>Throw exception when masterkey file is malformed<commit_after>/*******************************************************************************
 * Copyright (c) 2017 Skymatic UG (haftungsbeschränkt).
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the accompanying LICENSE file.
 *******************************************************************************/
package org.cryptomator.cryptofs.migration;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Map;
import java.util.Optional;

import javax.inject.Inject;

import org.cryptomator.cryptofs.common.Constants;
import org.cryptomator.cryptofs.common.FileSystemCapabilityChecker;
import org.cryptomator.cryptofs.migration.api.MigrationProgressListener;
import org.cryptomator.cryptofs.migration.api.Migrator;
import org.cryptomator.cryptofs.migration.api.NoApplicableMigratorException;
import org.cryptomator.cryptolib.Cryptors;
import org.cryptomator.cryptolib.api.InvalidPassphraseException;
import org.cryptomator.cryptolib.api.KeyFile;
import org.cryptomator.cryptolib.api.UnsupportedVaultFormatException;

/**
 * Used to perform migration from an older vault format to a newer one.
 * <p>
 * Example Usage:
 * 
 * <pre>
 * <code>
 * if (Migrators.get().{@link #needsMigration(Path, String) needsMigration(pathToVault, masterkeyFileName)}) {
 * 	Migrators.get().{@link #migrate(Path, String, CharSequence, MigrationProgressListener) migrate(pathToVault, masterkeyFileName, passphrase, migrationProgressListener)};
 * }
 * </code>
 * </pre>
 * 
 * @since 1.4.0
 */
public class Migrators {

	private static final MigrationComponent COMPONENT = DaggerMigrationComponent.builder() //
			.migrationModule(new MigrationModule(Cryptors.version1(strongSecureRandom()))) //
			.build();

	private final Map<Migration, Migrator> migrators;
	private final FileSystemCapabilityChecker fsCapabilityChecker;

	@Inject
	Migrators(Map<Migration, Migrator> migrators, FileSystemCapabilityChecker fsCapabilityChecker) {
		this.migrators = migrators;
		this.fsCapabilityChecker = fsCapabilityChecker;
	}

	private static SecureRandom strongSecureRandom() {
		try {
			return SecureRandom.getInstanceStrong();
		} catch (NoSuchAlgorithmException e) {
			throw new IllegalStateException("A strong algorithm must exist in every Java platform.", e);
		}
	}

	public static Migrators get() {
		return COMPONENT.migrators();
	}

	/**
	 * Inspects the vault and checks if it is supported by this library.
	 * 
	 * @param pathToVault Path to the vault's root
	 * @param masterkeyFilename Name of the masterkey file located in the vault
	 * @return <code>true</code> if the vault at the given path is of an older format than supported by this library
	 * @throws IOException if an I/O error occurs parsing the masterkey file
	 */
	public boolean needsMigration(Path pathToVault, String masterkeyFilename) throws IOException {
		Path masterKeyPath = pathToVault.resolve(masterkeyFilename);
		byte[] keyFileContents = Files.readAllBytes(masterKeyPath);
		try {
			KeyFile keyFile = KeyFile.parse(keyFileContents);
			return keyFile.getVersion() < Constants.VAULT_VERSION;
		} catch (IllegalArgumentException e) {
			throw new IOException("Malformed masterkey file " + masterKeyPath, e);
		}
	}

	/**
	 * Performs the actual migration. This task may take a while and this method will block.
	 * 
	 * @param pathToVault Path to the vault's root
	 * @param masterkeyFilename Name of the masterkey file located in the vault
	 * @param passphrase The passphrase needed to unlock the vault
	 * @throws NoApplicableMigratorException If the vault can not be migrated, because no migrator could be found
	 * @throws InvalidPassphraseException If the passphrase could not be used to unlock the vault
	 * @throws FileSystemCapabilityChecker.MissingCapabilityException If the underlying filesystem lacks features required to store a vault
	 * @throws IOException if an I/O error occurs migrating the vault
	 */
	public void migrate(Path pathToVault, String masterkeyFilename, CharSequence passphrase, MigrationProgressListener progressListener) throws NoApplicableMigratorException, InvalidPassphraseException, IOException {
		fsCapabilityChecker.assertAllCapabilities(pathToVault);
		
{'fraction_non_alphanumeric': 0.11369958275382476, 'fraction_numerical': 0.0018544274455261937, 'mean_word_length': 5.622409823484267, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2652376', 'n_tokens_mistral': 2492, 'n_tokens_neox': 2322, 'n_words': 711}