Refactor CryConfigCreator (factor out CryConfigConsole). This is preparation for adding a 'use default config' question.

This commit is contained in:
Sebastian Messmer 2016-01-17 14:57:40 +01:00
parent e2ab25803c
commit 16bdbcc2ca
9 changed files with 104 additions and 53 deletions

View File

@ -56,6 +56,7 @@ using std::make_shared;
using std::unique_ptr;
using std::make_unique;
using std::function;
using std::make_shared;
using boost::optional;
using boost::none;
using boost::chrono::duration;
@ -173,8 +174,8 @@ namespace cryfs {
CryConfigFile Cli::_loadOrCreateConfig(const ProgramOptions &options) {
try {
auto configFile = _determineConfigFile(options);
auto console = make_unique_ref<IOStreamConsole>();
auto config = CryConfigLoader(std::move(console), _keyGenerator, _scryptSettings,
auto console = make_shared<IOStreamConsole>();
auto config = CryConfigLoader(console, _keyGenerator, _scryptSettings,
std::bind(&Cli::_getPassword, this, std::cref(options), &Cli::_askPasswordForExistingFilesystem),
std::bind(&Cli::_getPassword, this, std::cref(options), &Cli::_askPasswordForNewFilesystem),
options.cipher()).loadOrCreate(configFile);

View File

@ -0,0 +1,36 @@
#include "CryConfigConsole.h"
#include "CryCipher.h"
using cpputils::unique_ref;
using cpputils::Console;
using boost::optional;
using boost::none;
using std::string;
using std::vector;
using std::shared_ptr;
namespace cryfs {
CryConfigConsole::CryConfigConsole(shared_ptr<Console> console)
: _console(std::move(console)) {
}
string CryConfigConsole::askCipher() const {
vector<string> ciphers = CryCiphers::supportedCipherNames();
string cipherName = "";
bool askAgain = true;
while(askAgain) {
int cipherIndex = _console->ask("Which block cipher do you want to use?", ciphers);
cipherName = ciphers[cipherIndex];
askAgain = !_showWarningForCipherAndReturnIfOk(cipherName);
};
return cipherName;
}
bool CryConfigConsole::_showWarningForCipherAndReturnIfOk(const string &cipherName) const {
auto warning = CryCiphers::find(cipherName).warning();
if (warning == none) {
return true;
}
return _console->askYesNo(string() + (*warning) + " Do you want to take this cipher nevertheless?");
}
}

View File

@ -0,0 +1,33 @@
#pragma once
#ifndef MESSMER_CRYFS_SRC_CONFIG_CRYCONFIGCONSOLE_H
#define MESSMER_CRYFS_SRC_CONFIG_CRYCONFIGCONSOLE_H
#include <messmer/cpp-utils/pointer/unique_ref.h>
#include <messmer/cpp-utils/io/Console.h>
#include <boost/optional.hpp>
namespace cryfs {
//TODO Test
class CryConfigConsole final {
public:
struct Config {
std::string cipher;
};
CryConfigConsole(std::shared_ptr<cpputils::Console> console);
CryConfigConsole(CryConfigConsole &&rhs) = default;
std::string askCipher() const;
private:
static constexpr const char *DEFAULT_CIPHER = "aes-256-gcm";
bool _showWarningForCipherAndReturnIfOk(const std::string &cipherName) const;
std::shared_ptr<cpputils::Console> _console;
DISALLOW_COPY_AND_ASSIGN(CryConfigConsole);
};
}
#endif

View File

@ -5,53 +5,34 @@ using cpputils::Console;
using cpputils::unique_ref;
using cpputils::RandomGenerator;
using std::string;
using std::shared_ptr;
using std::vector;
using boost::optional;
using boost::none;
namespace cryfs {
CryConfigCreator::CryConfigCreator(unique_ref<Console> console, RandomGenerator &encryptionKeyGenerator)
:_console(std::move(console)), _encryptionKeyGenerator(encryptionKeyGenerator) {
CryConfigCreator::CryConfigCreator(shared_ptr<Console> console, RandomGenerator &encryptionKeyGenerator)
:_console(console), _configConsole(console), _encryptionKeyGenerator(encryptionKeyGenerator) {
}
CryConfig CryConfigCreator::create(const optional<string> &cipher) {
CryConfig CryConfigCreator::create(const optional<string> &cipherFromCommandLine) {
CryConfig config;
config.SetCipher(_generateCipher(cipher));
config.SetCipher(_generateCipher(cipherFromCommandLine));
config.SetEncryptionKey(_generateEncKey(config.Cipher()));
config.SetRootBlob(_generateRootBlobKey());
return config;
}
string CryConfigCreator::_generateCipher(const optional<string> &cipher) {
if (cipher != none) {
ASSERT(std::find(CryCiphers::supportedCipherNames().begin(), CryCiphers::supportedCipherNames().end(), *cipher) != CryCiphers::supportedCipherNames().end(), "Invalid cipher");
return *cipher;
string CryConfigCreator::_generateCipher(const optional<string> &cipherFromCommandLine) {
if (cipherFromCommandLine != none) {
ASSERT(std::find(CryCiphers::supportedCipherNames().begin(), CryCiphers::supportedCipherNames().end(), *cipherFromCommandLine) != CryCiphers::supportedCipherNames().end(), "Invalid cipher");
return *cipherFromCommandLine;
} else {
return _askCipher();
return _configConsole.askCipher();
}
}
string CryConfigCreator::_askCipher() {
vector<string> ciphers = CryCiphers::supportedCipherNames();
string cipherName = "";
bool askAgain = true;
while(askAgain) {
int cipherIndex = _console->ask("Which block cipher do you want to use?", ciphers);
cipherName = ciphers[cipherIndex];
askAgain = !_showWarningForCipherAndReturnIfOk(cipherName);
};
return cipherName;
}
bool CryConfigCreator::_showWarningForCipherAndReturnIfOk(const string &cipherName) {
auto warning = CryCiphers::find(cipherName).warning();
if (warning == boost::none) {
return true;
}
return _console->askYesNo(string() + (*warning) + " Do you want to take this cipher nevertheless?");
}
string CryConfigCreator::_generateEncKey(const std::string &cipher) {
_console->print("\nGenerating secure encryption key...");
auto key = CryCiphers::find(cipher).createKey(_encryptionKeyGenerator);
@ -63,5 +44,4 @@ namespace cryfs {
//An empty root blob entry will tell CryDevice to create a new root blob
return "";
}
}
}

View File

@ -6,22 +6,22 @@
#include <messmer/cpp-utils/random/RandomGenerator.h>
#include <messmer/cpp-utils/io/Console.h>
#include "CryConfig.h"
#include "CryConfigConsole.h"
namespace cryfs {
class CryConfigCreator final {
public:
CryConfigCreator(cpputils::unique_ref<cpputils::Console> console, cpputils::RandomGenerator &encryptionKeyGenerator);
CryConfigCreator(std::shared_ptr<cpputils::Console> console, cpputils::RandomGenerator &encryptionKeyGenerator);
CryConfigCreator(CryConfigCreator &&rhs) = default;
CryConfig create(const boost::optional<std::string> &cipher);
CryConfig create(const boost::optional<std::string> &cipherFromCommandLine);
private:
std::string _generateCipher(const boost::optional<std::string> &cipher);
std::string _askCipher();
std::string _generateCipher(const boost::optional<std::string> &cipherFromCommandLine);
std::string _generateEncKey(const std::string &cipher);
std::string _generateRootBlobKey();
bool _showWarningForCipherAndReturnIfOk(const std::string &cipherName);
cpputils::unique_ref<cpputils::Console> _console;
std::shared_ptr<cpputils::Console> _console;
CryConfigConsole _configConsole;
cpputils::RandomGenerator &_encryptionKeyGenerator;
DISALLOW_COPY_AND_ASSIGN(CryConfigCreator);

View File

@ -14,6 +14,7 @@ using cpputils::RandomGenerator;
using cpputils::SCryptSettings;
using boost::optional;
using boost::none;
using std::shared_ptr;
using std::vector;
using std::string;
using std::function;
@ -22,10 +23,10 @@ using namespace cpputils::logging;
namespace cryfs {
CryConfigLoader::CryConfigLoader(unique_ref<Console> console, RandomGenerator &keyGenerator, const SCryptSettings &scryptSettings, function<string()> askPasswordForExistingFilesystem, function<string()> askPasswordForNewFilesystem, const optional<string> &cipher)
CryConfigLoader::CryConfigLoader(shared_ptr<Console> console, RandomGenerator &keyGenerator, const SCryptSettings &scryptSettings, function<string()> askPasswordForExistingFilesystem, function<string()> askPasswordForNewFilesystem, const optional<string> &cipherFromCommandLine)
: _creator(std::move(console), keyGenerator), _scryptSettings(scryptSettings),
_askPasswordForExistingFilesystem(askPasswordForExistingFilesystem), _askPasswordForNewFilesystem(askPasswordForNewFilesystem),
_cipher(cipher) {
_cipherFromCommandLine(cipherFromCommandLine) {
}
optional<CryConfigFile> CryConfigLoader::_loadConfig(const bf::path &filename) {
@ -37,8 +38,8 @@ optional<CryConfigFile> CryConfigLoader::_loadConfig(const bf::path &filename) {
return none;
}
std::cout << "done" << std::endl;
if (_cipher != none && config->config()->Cipher() != *_cipher) {
throw std::runtime_error("Filesystem uses "+config->config()->Cipher()+" cipher and not "+*_cipher+" as specified.");
if (_cipherFromCommandLine != none && config->config()->Cipher() != *_cipherFromCommandLine) {
throw std::runtime_error("Filesystem uses "+config->config()->Cipher()+" cipher and not "+*_cipherFromCommandLine+" as specified.");
}
return std::move(*config);
}
@ -52,7 +53,7 @@ optional<CryConfigFile> CryConfigLoader::loadOrCreate(const bf::path &filename)
}
CryConfigFile CryConfigLoader::_createConfig(const bf::path &filename) {
auto config = _creator.create(_cipher);
auto config = _creator.create(_cipherFromCommandLine);
//TODO Ask confirmation if using insecure password (<8 characters)
string password = _askPasswordForNewFilesystem();
std::cout << "Creating config file..." << std::flush;

View File

@ -13,7 +13,7 @@ namespace cryfs {
class CryConfigLoader final {
public:
CryConfigLoader(cpputils::unique_ref<cpputils::Console> console, cpputils::RandomGenerator &keyGenerator, const cpputils::SCryptSettings &scryptSettings, std::function<std::string()> askPasswordForExistingFilesystem, std::function<std::string()> askPasswordForNewFilesystem, const boost::optional<std::string> &cipher);
CryConfigLoader(std::shared_ptr<cpputils::Console> console, cpputils::RandomGenerator &keyGenerator, const cpputils::SCryptSettings &scryptSettings, std::function<std::string()> askPasswordForExistingFilesystem, std::function<std::string()> askPasswordForNewFilesystem, const boost::optional<std::string> &cipherFromCommandLine);
CryConfigLoader(CryConfigLoader &&rhs) = default;
boost::optional<CryConfigFile> loadOrCreate(const boost::filesystem::path &filename);
@ -26,7 +26,7 @@ private:
cpputils::SCryptSettings _scryptSettings;
std::function<std::string()> _askPasswordForExistingFilesystem;
std::function<std::string()> _askPasswordForNewFilesystem;
boost::optional<std::string> _cipher;
boost::optional<std::string> _cipherFromCommandLine;
DISALLOW_COPY_AND_ASSIGN(CryConfigLoader);
};

View File

@ -14,6 +14,8 @@ using cpputils::unique_ref;
using cpputils::make_unique_ref;
using std::string;
using std::vector;
using std::shared_ptr;
using std::make_shared;
using ::testing::_;
using ::testing::Return;
using ::testing::Invoke;
@ -25,12 +27,10 @@ using ::testing::WithParamInterface;
class CryConfigCreatorTest: public ::testing::Test {
public:
CryConfigCreatorTest()
: _console(make_unique_ref<MockConsole>()),
console(_console.get()),
creator(std::move(_console), cpputils::Random::PseudoRandom()) {
: console(make_shared<MockConsole>()),
creator(console, cpputils::Random::PseudoRandom()) {
}
unique_ref<MockConsole> _console;
MockConsole *console;
shared_ptr<MockConsole> console;
CryConfigCreator creator;
};

View File

@ -21,8 +21,8 @@ ACTION_P(ChooseCipher, cipherName) {
class TestWithMockConsole {
public:
// Return a console that chooses a valid cryfs setting
static cpputils::unique_ref<MockConsole> mockConsole() {
auto console = cpputils::make_unique_ref<MockConsole>();
static std::shared_ptr<MockConsole> mockConsole() {
auto console = std::make_shared<MockConsole>();
EXPECT_CALL(*console, ask(::testing::_, ::testing::_)).WillRepeatedly(ChooseCipher("aes-256-gcm"));
EXPECT_CALL(*console, askYesNo(::testing::_)).WillRepeatedly(::testing::Return(true));
return console;