If CRYFS_FRONTEND=noninteractive is set in the environment, assume we're used by a tool and:
- Don't ask for config. Use default settings for everything that is not specified as command line parameter. - Don't ask for password confirmation. Password only has to be passed in once to stdin.
This commit is contained in:
parent
346baf8e9b
commit
9c83d3b2a4
@ -1,3 +1,9 @@
|
|||||||
|
Version 0.9.3 (unreleased)
|
||||||
|
---------------
|
||||||
|
* It's easier for tools and scripts to use CryFS:
|
||||||
|
If an environment variable CRYFS_FRONTEND=noninteractive is set, we don't ask for options (but take default values for everything that's not specified on command line).
|
||||||
|
Furthermore, we won't ask for password confirmation when creating a file system but the password only has to be sent once to stdin.
|
||||||
|
|
||||||
Version 0.9.2
|
Version 0.9.2
|
||||||
---------------
|
---------------
|
||||||
* Experimental support for installing CryFS on Mac OS X using homebrew
|
* Experimental support for installing CryFS on Mac OS X using homebrew
|
||||||
|
@ -70,9 +70,16 @@ using cpputils::dynamic_pointer_move;
|
|||||||
//TODO Performance difference when setting compiler parameter -maes for scrypt?
|
//TODO Performance difference when setting compiler parameter -maes for scrypt?
|
||||||
|
|
||||||
namespace cryfs {
|
namespace cryfs {
|
||||||
|
const string Cli::CRYFS_FRONTEND_KEY = "CRYFS_FRONTEND";
|
||||||
|
const string Cli::CRYFS_FRONTEND_NONINTERACTIVE = "noninteractive";
|
||||||
|
|
||||||
Cli::Cli(RandomGenerator &keyGenerator, const SCryptSettings &scryptSettings, shared_ptr<Console> console, shared_ptr<HttpClient> httpClient):
|
Cli::Cli(RandomGenerator &keyGenerator, const SCryptSettings &scryptSettings, shared_ptr<Console> console, shared_ptr<HttpClient> httpClient):
|
||||||
_keyGenerator(keyGenerator), _scryptSettings(scryptSettings), _console(console), _httpClient(httpClient) {}
|
_keyGenerator(keyGenerator), _scryptSettings(scryptSettings), _console(console), _httpClient(httpClient), _noninteractive(false) {
|
||||||
|
char *frontend = std::getenv(CRYFS_FRONTEND_KEY.c_str());
|
||||||
|
if (frontend != nullptr && frontend == CRYFS_FRONTEND_NONINTERACTIVE) {
|
||||||
|
_noninteractive = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Cli::_showVersion() {
|
void Cli::_showVersion() {
|
||||||
cout << "CryFS Version " << version::VERSION_STRING << endl;
|
cout << "CryFS Version " << version::VERSION_STRING << endl;
|
||||||
@ -110,19 +117,6 @@ namespace cryfs {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
string Cli::_getPassword(function<string()> askPassword) {
|
|
||||||
string password = askPassword();
|
|
||||||
//Remove trailing newline
|
|
||||||
if (password[password.size()-1] == '\n') {
|
|
||||||
password.resize(password.size()-1);
|
|
||||||
}
|
|
||||||
//Check that password is valid
|
|
||||||
if (!_checkPassword(password)) {
|
|
||||||
throw std::runtime_error("Password invalid.");
|
|
||||||
}
|
|
||||||
return password;
|
|
||||||
}
|
|
||||||
|
|
||||||
string Cli::_askPasswordForExistingFilesystem() {
|
string Cli::_askPasswordForExistingFilesystem() {
|
||||||
string password = _askPasswordFromStdin("Password: ");
|
string password = _askPasswordFromStdin("Password: ");
|
||||||
while (!_checkPassword(password)) {
|
while (!_checkPassword(password)) {
|
||||||
@ -158,6 +152,15 @@ namespace cryfs {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string Cli::_askPasswordNoninteractive() {
|
||||||
|
//TODO Test
|
||||||
|
string password = _askPasswordFromStdin("Password: ");
|
||||||
|
if (!_checkPassword(password)) {
|
||||||
|
throw std::runtime_error("Invalid password. Password cannot be empty.");
|
||||||
|
}
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
string Cli::_askPasswordFromStdin(const string &prompt) {
|
string Cli::_askPasswordFromStdin(const string &prompt) {
|
||||||
DontEchoStdinToStdoutRAII _stdin_input_is_hidden_as_long_as_this_is_in_scope;
|
DontEchoStdinToStdoutRAII _stdin_input_is_hidden_as_long_as_this_is_in_scope;
|
||||||
|
|
||||||
@ -166,6 +169,11 @@ namespace cryfs {
|
|||||||
std::getline(cin, result);
|
std::getline(cin, result);
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
//Remove trailing newline
|
||||||
|
if (result[result.size()-1] == '\n') {
|
||||||
|
result.resize(result.size()-1);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,10 +188,7 @@ namespace cryfs {
|
|||||||
CryConfigFile Cli::_loadOrCreateConfig(const ProgramOptions &options) {
|
CryConfigFile Cli::_loadOrCreateConfig(const ProgramOptions &options) {
|
||||||
try {
|
try {
|
||||||
auto configFile = _determineConfigFile(options);
|
auto configFile = _determineConfigFile(options);
|
||||||
auto config = CryConfigLoader(_console, _keyGenerator, _scryptSettings,
|
auto config = _loadOrCreateConfigFile(configFile, options.cipher());
|
||||||
std::bind(&Cli::_getPassword, this, &Cli::_askPasswordForExistingFilesystem),
|
|
||||||
std::bind(&Cli::_getPassword, this, &Cli::_askPasswordForNewFilesystem),
|
|
||||||
options.cipher()).loadOrCreate(configFile);
|
|
||||||
if (config == none) {
|
if (config == none) {
|
||||||
std::cerr << "Could not load config file. Did you enter the correct password?" << std::endl;
|
std::cerr << "Could not load config file. Did you enter the correct password?" << std::endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
@ -195,6 +200,20 @@ namespace cryfs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
optional<CryConfigFile> Cli::_loadOrCreateConfigFile(const bf::path &configFilePath, const optional<string> &cipher) {
|
||||||
|
if (_noninteractive) {
|
||||||
|
return CryConfigLoader(_console, _keyGenerator, _scryptSettings,
|
||||||
|
&Cli::_askPasswordNoninteractive,
|
||||||
|
&Cli::_askPasswordNoninteractive,
|
||||||
|
cipher, _noninteractive).loadOrCreate(configFilePath);
|
||||||
|
} else {
|
||||||
|
return CryConfigLoader(_console, _keyGenerator, _scryptSettings,
|
||||||
|
&Cli::_askPasswordForExistingFilesystem,
|
||||||
|
&Cli::_askPasswordForNewFilesystem,
|
||||||
|
cipher, _noninteractive).loadOrCreate(configFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Cli::_runFilesystem(const ProgramOptions &options) {
|
void Cli::_runFilesystem(const ProgramOptions &options) {
|
||||||
try {
|
try {
|
||||||
auto blockStore = make_unique_ref<OnDiskBlockStore>(options.baseDir());
|
auto blockStore = make_unique_ref<OnDiskBlockStore>(options.baseDir());
|
||||||
@ -269,6 +288,10 @@ namespace cryfs {
|
|||||||
|
|
||||||
void Cli::_checkDirAccessible(const bf::path &dir, const std::string &name) {
|
void Cli::_checkDirAccessible(const bf::path &dir, const std::string &name) {
|
||||||
if (!bf::exists(dir)) {
|
if (!bf::exists(dir)) {
|
||||||
|
if (_noninteractive) {
|
||||||
|
//If we use the noninteractive frontend, don't ask whether to create the directory, but just fail.
|
||||||
|
throw std::runtime_error(name + " not found");
|
||||||
|
}
|
||||||
bool create = _console->askYesNo("Could not find " + name + ". Do you want to create it?");
|
bool create = _console->askYesNo("Could not find " + name + ". Do you want to create it?");
|
||||||
if (create) {
|
if (create) {
|
||||||
if (!bf::create_directory(dir)) {
|
if (!bf::create_directory(dir)) {
|
||||||
|
@ -21,10 +21,11 @@ namespace cryfs {
|
|||||||
private:
|
private:
|
||||||
void _runFilesystem(const program_options::ProgramOptions &options);
|
void _runFilesystem(const program_options::ProgramOptions &options);
|
||||||
CryConfigFile _loadOrCreateConfig(const program_options::ProgramOptions &options);
|
CryConfigFile _loadOrCreateConfig(const program_options::ProgramOptions &options);
|
||||||
|
boost::optional<CryConfigFile> _loadOrCreateConfigFile(const boost::filesystem::path &configFilePath, const boost::optional<std::string> &cipher);
|
||||||
boost::filesystem::path _determineConfigFile(const program_options::ProgramOptions &options);
|
boost::filesystem::path _determineConfigFile(const program_options::ProgramOptions &options);
|
||||||
std::string _getPassword(std::function<std::string()> askPassword);
|
|
||||||
static std::string _askPasswordForExistingFilesystem();
|
static std::string _askPasswordForExistingFilesystem();
|
||||||
static std::string _askPasswordForNewFilesystem();
|
static std::string _askPasswordForNewFilesystem();
|
||||||
|
static std::string _askPasswordNoninteractive();
|
||||||
static std::string _askPasswordFromStdin(const std::string &prompt);
|
static std::string _askPasswordFromStdin(const std::string &prompt);
|
||||||
static bool _confirmPassword(const std::string &password);
|
static bool _confirmPassword(const std::string &password);
|
||||||
static bool _checkPassword(const std::string &password);
|
static bool _checkPassword(const std::string &password);
|
||||||
@ -39,10 +40,14 @@ namespace cryfs {
|
|||||||
boost::optional<cpputils::unique_ref<CallAfterTimeout>> _createIdleCallback(boost::optional<double> minutes, std::function<void()> callback);
|
boost::optional<cpputils::unique_ref<CallAfterTimeout>> _createIdleCallback(boost::optional<double> minutes, std::function<void()> callback);
|
||||||
void _sanityCheckFilesystem(CryDevice *device);
|
void _sanityCheckFilesystem(CryDevice *device);
|
||||||
|
|
||||||
|
static const std::string CRYFS_FRONTEND_KEY;
|
||||||
|
static const std::string CRYFS_FRONTEND_NONINTERACTIVE;
|
||||||
|
|
||||||
cpputils::RandomGenerator &_keyGenerator;
|
cpputils::RandomGenerator &_keyGenerator;
|
||||||
cpputils::SCryptSettings _scryptSettings;
|
cpputils::SCryptSettings _scryptSettings;
|
||||||
std::shared_ptr<cpputils::Console> _console;
|
std::shared_ptr<cpputils::Console> _console;
|
||||||
std::shared_ptr<cpputils::HttpClient> _httpClient;
|
std::shared_ptr<cpputils::HttpClient> _httpClient;
|
||||||
|
bool _noninteractive;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(Cli);
|
DISALLOW_COPY_AND_ASSIGN(Cli);
|
||||||
};
|
};
|
||||||
|
@ -12,8 +12,8 @@ using std::shared_ptr;
|
|||||||
namespace cryfs {
|
namespace cryfs {
|
||||||
constexpr const char *CryConfigConsole::DEFAULT_CIPHER;
|
constexpr const char *CryConfigConsole::DEFAULT_CIPHER;
|
||||||
|
|
||||||
CryConfigConsole::CryConfigConsole(shared_ptr<Console> console)
|
CryConfigConsole::CryConfigConsole(shared_ptr<Console> console, bool noninteractive)
|
||||||
: _console(std::move(console)), _useDefaultSettings(none) {
|
: _console(std::move(console)), _useDefaultSettings(noninteractive ? optional<bool>(true) : none) {
|
||||||
}
|
}
|
||||||
|
|
||||||
string CryConfigConsole::askCipher() {
|
string CryConfigConsole::askCipher() {
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
namespace cryfs {
|
namespace cryfs {
|
||||||
class CryConfigConsole final {
|
class CryConfigConsole final {
|
||||||
public:
|
public:
|
||||||
CryConfigConsole(std::shared_ptr<cpputils::Console> console);
|
CryConfigConsole(std::shared_ptr<cpputils::Console> console, bool noninteractive);
|
||||||
CryConfigConsole(CryConfigConsole &&rhs) = default;
|
CryConfigConsole(CryConfigConsole &&rhs) = default;
|
||||||
|
|
||||||
std::string askCipher();
|
std::string askCipher();
|
||||||
@ -17,6 +17,7 @@ namespace cryfs {
|
|||||||
static constexpr const char *DEFAULT_CIPHER = "aes-256-gcm";
|
static constexpr const char *DEFAULT_CIPHER = "aes-256-gcm";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool _checkUseDefaultSettings();
|
bool _checkUseDefaultSettings();
|
||||||
|
|
||||||
std::string _askCipher() const;
|
std::string _askCipher() const;
|
||||||
|
@ -13,8 +13,8 @@ using boost::none;
|
|||||||
|
|
||||||
namespace cryfs {
|
namespace cryfs {
|
||||||
|
|
||||||
CryConfigCreator::CryConfigCreator(shared_ptr<Console> console, RandomGenerator &encryptionKeyGenerator)
|
CryConfigCreator::CryConfigCreator(shared_ptr<Console> console, RandomGenerator &encryptionKeyGenerator, bool noninteractive)
|
||||||
:_console(console), _configConsole(console), _encryptionKeyGenerator(encryptionKeyGenerator) {
|
:_console(console), _configConsole(console, noninteractive), _encryptionKeyGenerator(encryptionKeyGenerator) {
|
||||||
}
|
}
|
||||||
|
|
||||||
CryConfig CryConfigCreator::create(const optional<string> &cipherFromCommandLine) {
|
CryConfig CryConfigCreator::create(const optional<string> &cipherFromCommandLine) {
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
namespace cryfs {
|
namespace cryfs {
|
||||||
class CryConfigCreator final {
|
class CryConfigCreator final {
|
||||||
public:
|
public:
|
||||||
CryConfigCreator(std::shared_ptr<cpputils::Console> console, cpputils::RandomGenerator &encryptionKeyGenerator);
|
CryConfigCreator(std::shared_ptr<cpputils::Console> console, cpputils::RandomGenerator &encryptionKeyGenerator, bool noninteractive);
|
||||||
CryConfigCreator(CryConfigCreator &&rhs) = default;
|
CryConfigCreator(CryConfigCreator &&rhs) = default;
|
||||||
|
|
||||||
CryConfig create(const boost::optional<std::string> &cipherFromCommandLine);
|
CryConfig create(const boost::optional<std::string> &cipherFromCommandLine);
|
||||||
|
@ -25,8 +25,8 @@ using namespace cpputils::logging;
|
|||||||
|
|
||||||
namespace cryfs {
|
namespace cryfs {
|
||||||
|
|
||||||
CryConfigLoader::CryConfigLoader(shared_ptr<Console> console, RandomGenerator &keyGenerator, const SCryptSettings &scryptSettings, function<string()> askPasswordForExistingFilesystem, function<string()> askPasswordForNewFilesystem, const optional<string> &cipherFromCommandLine)
|
CryConfigLoader::CryConfigLoader(shared_ptr<Console> console, RandomGenerator &keyGenerator, const SCryptSettings &scryptSettings, function<string()> askPasswordForExistingFilesystem, function<string()> askPasswordForNewFilesystem, const optional<string> &cipherFromCommandLine, bool noninteractive)
|
||||||
: _creator(std::move(console), keyGenerator), _scryptSettings(scryptSettings),
|
: _creator(std::move(console), keyGenerator, noninteractive), _scryptSettings(scryptSettings),
|
||||||
_askPasswordForExistingFilesystem(askPasswordForExistingFilesystem), _askPasswordForNewFilesystem(askPasswordForNewFilesystem),
|
_askPasswordForExistingFilesystem(askPasswordForExistingFilesystem), _askPasswordForNewFilesystem(askPasswordForNewFilesystem),
|
||||||
_cipherFromCommandLine(cipherFromCommandLine) {
|
_cipherFromCommandLine(cipherFromCommandLine) {
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ namespace cryfs {
|
|||||||
|
|
||||||
class CryConfigLoader final {
|
class CryConfigLoader final {
|
||||||
public:
|
public:
|
||||||
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(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, bool noninteractive);
|
||||||
CryConfigLoader(CryConfigLoader &&rhs) = default;
|
CryConfigLoader(CryConfigLoader &&rhs) = default;
|
||||||
|
|
||||||
boost::optional<CryConfigFile> loadOrCreate(const boost::filesystem::path &filename);
|
boost::optional<CryConfigFile> loadOrCreate(const boost::filesystem::path &filename);
|
||||||
|
@ -4,6 +4,7 @@ namespace bf = boost::filesystem;
|
|||||||
using ::testing::Values;
|
using ::testing::Values;
|
||||||
using ::testing::WithParamInterface;
|
using ::testing::WithParamInterface;
|
||||||
using ::testing::Return;
|
using ::testing::Return;
|
||||||
|
using ::testing::_;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
using cpputils::TempFile;
|
using cpputils::TempFile;
|
||||||
|
|
||||||
@ -116,10 +117,21 @@ TEST_P(CliTest_WrongEnvironment, MountDirIsBaseDir_BothRelative) {
|
|||||||
|
|
||||||
TEST_P(CliTest_WrongEnvironment, BaseDir_DoesntExist) {
|
TEST_P(CliTest_WrongEnvironment, BaseDir_DoesntExist) {
|
||||||
_basedir.remove();
|
_basedir.remove();
|
||||||
ON_CALL(*console, askYesNo("Could not find base directory. Do you want to create it?")).WillByDefault(Return(false)); // ON_CALL and not EXPECT_CALL, because this is a death test (i.e. it is forked) and gmock EXPECT_CALL in fork children don't report to parents.
|
// ON_CALL and not EXPECT_CALL, because this is a death test (i.e. it is forked) and gmock EXPECT_CALL in fork children don't report to parents.
|
||||||
|
ON_CALL(*console, askYesNo("Could not find base directory. Do you want to create it?")).WillByDefault(Return(false));
|
||||||
Test_Run_Error("Error: base directory not found");
|
Test_Run_Error("Error: base directory not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_P(CliTest_WrongEnvironment, BaseDir_DoesntExist_Noninteractive) {
|
||||||
|
_basedir.remove();
|
||||||
|
// We can't set an EXPECT_CALL().Times(0), because this is a death test (i.e. it is forked) and gmock EXPECT_CALL in fork children don't report to parents.
|
||||||
|
// So we set a default answer that shouldn't crash and check it's not called by checking that it crashes.
|
||||||
|
ON_CALL(*console, askYesNo("Could not find base directory. Do you want to create it?")).WillByDefault(Return(true));
|
||||||
|
::setenv("CRYFS_FRONTEND", "noninteractive", 1);
|
||||||
|
Test_Run_Error("Error: base directory not found");
|
||||||
|
::unsetenv("CRYFS_FRONTEND");
|
||||||
|
}
|
||||||
|
|
||||||
TEST_P(CliTest_WrongEnvironment, BaseDir_DoesntExist_Create) {
|
TEST_P(CliTest_WrongEnvironment, BaseDir_DoesntExist_Create) {
|
||||||
if (!GetParam().runningInForeground) {return;} // TODO Make this work also if run in background (see CliTest::EXPECT_RUN_SUCCESS)
|
if (!GetParam().runningInForeground) {return;} // TODO Make this work also if run in background (see CliTest::EXPECT_RUN_SUCCESS)
|
||||||
_basedir.remove();
|
_basedir.remove();
|
||||||
@ -163,10 +175,21 @@ TEST_P(CliTest_WrongEnvironment, BaseDir_NoPermission) {
|
|||||||
|
|
||||||
TEST_P(CliTest_WrongEnvironment, MountDir_DoesntExist) {
|
TEST_P(CliTest_WrongEnvironment, MountDir_DoesntExist) {
|
||||||
_mountdir.remove();
|
_mountdir.remove();
|
||||||
ON_CALL(*console, askYesNo("Could not find mount directory. Do you want to create it?")).WillByDefault(Return(false)); // ON_CALL and not EXPECT_CALL, because this is a death test (i.e. it is forked) and gmock EXPECT_CALL in fork children don't report to parents.
|
// ON_CALL and not EXPECT_CALL, because this is a death test (i.e. it is forked) and gmock EXPECT_CALL in fork children don't report to parents.
|
||||||
|
ON_CALL(*console, askYesNo("Could not find mount directory. Do you want to create it?")).WillByDefault(Return(false));
|
||||||
Test_Run_Error("Error: mount directory not found");
|
Test_Run_Error("Error: mount directory not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_P(CliTest_WrongEnvironment, MountDir_DoesntExist_Noninteractive) {
|
||||||
|
_mountdir.remove();
|
||||||
|
// We can't set an EXPECT_CALL().Times(0), because this is a death test (i.e. it is forked) and gmock EXPECT_CALL in fork children don't report to parents.
|
||||||
|
// So we set a default answer that shouldn't crash and check it's not called by checking that it crashes.
|
||||||
|
ON_CALL(*console, askYesNo("Could not find base directory. Do you want to create it?")).WillByDefault(Return(true));
|
||||||
|
::setenv("CRYFS_FRONTEND", "noninteractive", 1);
|
||||||
|
Test_Run_Error("Error: mount directory not found");
|
||||||
|
::unsetenv("CRYFS_FRONTEND");
|
||||||
|
}
|
||||||
|
|
||||||
TEST_P(CliTest_WrongEnvironment, MountDir_DoesntExist_Create) {
|
TEST_P(CliTest_WrongEnvironment, MountDir_DoesntExist_Create) {
|
||||||
if (!GetParam().runningInForeground) {return;} // TODO Make this work also if run in background (see CliTest::EXPECT_RUN_SUCCESS)
|
if (!GetParam().runningInForeground) {return;} // TODO Make this work also if run in background (see CliTest::EXPECT_RUN_SUCCESS)
|
||||||
_mountdir.remove();
|
_mountdir.remove();
|
||||||
|
@ -28,10 +28,12 @@ class CryConfigConsoleTest: public ::testing::Test {
|
|||||||
public:
|
public:
|
||||||
CryConfigConsoleTest()
|
CryConfigConsoleTest()
|
||||||
: console(make_shared<MockConsole>()),
|
: console(make_shared<MockConsole>()),
|
||||||
cryconsole(console) {
|
cryconsole(console, false),
|
||||||
|
noninteractiveCryconsole(console, true) {
|
||||||
}
|
}
|
||||||
shared_ptr<MockConsole> console;
|
shared_ptr<MockConsole> console;
|
||||||
CryConfigConsole cryconsole;
|
CryConfigConsole cryconsole;
|
||||||
|
CryConfigConsole noninteractiveCryconsole;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CryConfigConsoleTest_Cipher: public CryConfigConsoleTest {};
|
class CryConfigConsoleTest_Cipher: public CryConfigConsoleTest {};
|
||||||
@ -52,6 +54,13 @@ TEST_F(CryConfigConsoleTest_Cipher, ChooseDefaultCipher) {
|
|||||||
EXPECT_EQ(CryConfigConsole::DEFAULT_CIPHER, cipher);
|
EXPECT_EQ(CryConfigConsole::DEFAULT_CIPHER, cipher);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(CryConfigConsoleTest_Cipher, ChooseDefaultCipherWhenNoninteractiveEnvironment) {
|
||||||
|
EXPECT_CALL(*console, askYesNo(HasSubstr("default"))).Times(0);
|
||||||
|
EXPECT_CALL(*console, ask(HasSubstr("block cipher"), _)).Times(0);
|
||||||
|
string cipher = noninteractiveCryconsole.askCipher();
|
||||||
|
EXPECT_EQ(CryConfigConsole::DEFAULT_CIPHER, cipher);
|
||||||
|
}
|
||||||
|
|
||||||
class CryConfigConsoleTest_Cipher_Choose: public CryConfigConsoleTest_Cipher, public ::testing::WithParamInterface<string> {
|
class CryConfigConsoleTest_Cipher_Choose: public CryConfigConsoleTest_Cipher, public ::testing::WithParamInterface<string> {
|
||||||
public:
|
public:
|
||||||
string cipherName = GetParam();
|
string cipherName = GetParam();
|
||||||
|
@ -28,10 +28,12 @@ class CryConfigCreatorTest: public ::testing::Test {
|
|||||||
public:
|
public:
|
||||||
CryConfigCreatorTest()
|
CryConfigCreatorTest()
|
||||||
: console(make_shared<MockConsole>()),
|
: console(make_shared<MockConsole>()),
|
||||||
creator(console, cpputils::Random::PseudoRandom()) {
|
creator(console, cpputils::Random::PseudoRandom(), false),
|
||||||
|
noninteractiveCreator(console, cpputils::Random::PseudoRandom(), true) {
|
||||||
}
|
}
|
||||||
shared_ptr<MockConsole> console;
|
shared_ptr<MockConsole> console;
|
||||||
CryConfigCreator creator;
|
CryConfigCreator creator;
|
||||||
|
CryConfigCreator noninteractiveCreator;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define EXPECT_ASK_FOR_CIPHER() \
|
#define EXPECT_ASK_FOR_CIPHER() \
|
||||||
@ -51,6 +53,11 @@ TEST_F(CryConfigCreatorTest, DoesNotAskForCipherIfSpecified) {
|
|||||||
CryConfig config = creator.create(string("aes-256-gcm"));
|
CryConfig config = creator.create(string("aes-256-gcm"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(CryConfigCreatorTest, DoesNotAskForCipherIfNoninteractive) {
|
||||||
|
EXPECT_DOES_NOT_ASK_FOR_CIPHER();
|
||||||
|
CryConfig config = noninteractiveCreator.create(none);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(CryConfigCreatorTest, ChoosesEmptyRootBlobId) {
|
TEST_F(CryConfigCreatorTest, ChoosesEmptyRootBlobId) {
|
||||||
EXPECT_ASK_FOR_CIPHER().WillOnce(ChooseAnyCipher());
|
EXPECT_ASK_FOR_CIPHER().WillOnce(ChooseAnyCipher());
|
||||||
CryConfig config = creator.create(none);
|
CryConfig config = creator.create(none);
|
||||||
|
@ -26,41 +26,39 @@ namespace boost {
|
|||||||
}
|
}
|
||||||
#include <boost/optional/optional_io.hpp>
|
#include <boost/optional/optional_io.hpp>
|
||||||
|
|
||||||
//TODO Test loading with same/different --cipher argument
|
|
||||||
|
|
||||||
class CryConfigLoaderTest: public ::testing::Test, public TestWithMockConsole {
|
class CryConfigLoaderTest: public ::testing::Test, public TestWithMockConsole {
|
||||||
public:
|
public:
|
||||||
CryConfigLoaderTest(): file(false) {}
|
CryConfigLoaderTest(): file(false) {}
|
||||||
|
|
||||||
CryConfigLoader loader(const string &password, const optional<string> &cipher = none) {
|
CryConfigLoader loader(const string &password, bool noninteractive, const optional<string> &cipher = none) {
|
||||||
auto askPassword = [password] {return password;};
|
auto askPassword = [password] { return password;};
|
||||||
return CryConfigLoader(mockConsole(), cpputils::Random::PseudoRandom(), SCrypt::TestSettings, askPassword, askPassword, cipher);
|
return CryConfigLoader(mockConsole(), cpputils::Random::PseudoRandom(), SCrypt::TestSettings, askPassword, askPassword, cipher, noninteractive);
|
||||||
}
|
}
|
||||||
|
|
||||||
CryConfigFile Create(const string &password = "mypassword", const optional<string> &cipher = none) {
|
CryConfigFile Create(const string &password = "mypassword", const optional<string> &cipher = none, bool noninteractive = false) {
|
||||||
EXPECT_FALSE(file.exists());
|
EXPECT_FALSE(file.exists());
|
||||||
return loader(password, cipher).loadOrCreate(file.path()).value();
|
return loader(password, noninteractive, cipher).loadOrCreate(file.path()).value();
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<CryConfigFile> Load(const string &password = "mypassword", const optional<string> &cipher = none) {
|
optional<CryConfigFile> Load(const string &password = "mypassword", const optional<string> &cipher = none, bool noninteractive = false) {
|
||||||
EXPECT_TRUE(file.exists());
|
EXPECT_TRUE(file.exists());
|
||||||
return loader(password, cipher).loadOrCreate(file.path());
|
return loader(password, noninteractive, cipher).loadOrCreate(file.path());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateWithRootBlob(const string &rootBlob, const string &password = "mypassword") {
|
void CreateWithRootBlob(const string &rootBlob, const string &password = "mypassword") {
|
||||||
auto cfg = loader(password).loadOrCreate(file.path()).value();
|
auto cfg = loader(password, false).loadOrCreate(file.path()).value();
|
||||||
cfg.config()->SetRootBlob(rootBlob);
|
cfg.config()->SetRootBlob(rootBlob);
|
||||||
cfg.save();
|
cfg.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateWithCipher(const string &cipher, const string &password = "mypassword") {
|
void CreateWithCipher(const string &cipher, const string &password = "mypassword") {
|
||||||
auto cfg = loader(password).loadOrCreate(file.path()).value();
|
auto cfg = loader(password, false).loadOrCreate(file.path()).value();
|
||||||
cfg.config()->SetCipher(cipher);
|
cfg.config()->SetCipher(cipher);
|
||||||
cfg.save();
|
cfg.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateWithEncryptionKey(const string &encKey, const string &password = "mypassword") {
|
void CreateWithEncryptionKey(const string &encKey, const string &password = "mypassword") {
|
||||||
auto cfg = loader(password).loadOrCreate(file.path()).value();
|
auto cfg = loader(password, false).loadOrCreate(file.path()).value();
|
||||||
cfg.config()->SetEncryptionKey(encKey);
|
cfg.config()->SetEncryptionKey(encKey);
|
||||||
cfg.save();
|
cfg.save();
|
||||||
}
|
}
|
||||||
@ -86,9 +84,19 @@ TEST_F(CryConfigLoaderTest, DoesntLoadIfWrongPassword) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CryConfigLoaderTest, DoesntLoadIfDifferentCipher) {
|
TEST_F(CryConfigLoaderTest, DoesntLoadIfDifferentCipher) {
|
||||||
Create("mypassword", string("aes-256-gcm"));
|
Create("mypassword", string("aes-256-gcm"), false);
|
||||||
try {
|
try {
|
||||||
Load("mypassword", string("aes-256-cfb"));
|
Load("mypassword", string("aes-256-cfb"), false);
|
||||||
|
EXPECT_TRUE(false); // Should throw exception
|
||||||
|
} catch (const std::runtime_error &e) {
|
||||||
|
EXPECT_EQ(string("Filesystem uses aes-256-gcm cipher and not aes-256-cfb as specified."), e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CryConfigLoaderTest, DoesntLoadIfDifferentCipher_Noninteractive) {
|
||||||
|
Create("mypassword", string("aes-256-gcm"), true);
|
||||||
|
try {
|
||||||
|
Load("mypassword", string("aes-256-cfb"), true);
|
||||||
EXPECT_TRUE(false); // Should throw exception
|
EXPECT_TRUE(false); // Should throw exception
|
||||||
} catch (const std::runtime_error &e) {
|
} catch (const std::runtime_error &e) {
|
||||||
EXPECT_EQ(string("Filesystem uses aes-256-gcm cipher and not aes-256-cfb as specified."), e.what());
|
EXPECT_EQ(string("Filesystem uses aes-256-gcm cipher and not aes-256-cfb as specified."), e.what());
|
||||||
@ -100,6 +108,11 @@ TEST_F(CryConfigLoaderTest, DoesLoadIfSameCipher) {
|
|||||||
Load("mypassword", string("aes-256-gcm"));
|
Load("mypassword", string("aes-256-gcm"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(CryConfigLoaderTest, DoesLoadIfSameCipher_Noninteractive) {
|
||||||
|
Create("mypassword", string("aes-128-gcm"), true);
|
||||||
|
Load("mypassword", string("aes-128-gcm"), true);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(CryConfigLoaderTest, RootBlob_Load) {
|
TEST_F(CryConfigLoaderTest, RootBlob_Load) {
|
||||||
CreateWithRootBlob("rootblobid");
|
CreateWithRootBlob("rootblobid");
|
||||||
auto loaded = Load().value();
|
auto loaded = Load().value();
|
||||||
|
@ -37,7 +37,7 @@ public:
|
|||||||
|
|
||||||
CryConfigFile loadOrCreateConfig() {
|
CryConfigFile loadOrCreateConfig() {
|
||||||
auto askPassword = [] {return "mypassword";};
|
auto askPassword = [] {return "mypassword";};
|
||||||
return CryConfigLoader(mockConsole(), Random::PseudoRandom(), SCrypt::TestSettings, askPassword, askPassword, none).loadOrCreate(config.path()).value();
|
return CryConfigLoader(mockConsole(), Random::PseudoRandom(), SCrypt::TestSettings, askPassword, askPassword, none, true).loadOrCreate(config.path()).value();
|
||||||
}
|
}
|
||||||
|
|
||||||
unique_ref<OnDiskBlockStore> blockStore() {
|
unique_ref<OnDiskBlockStore> blockStore() {
|
||||||
|
@ -28,7 +28,7 @@ public:
|
|||||||
unique_ref<Device> createDevice() override {
|
unique_ref<Device> createDevice() override {
|
||||||
auto blockStore = cpputils::make_unique_ref<FakeBlockStore>();
|
auto blockStore = cpputils::make_unique_ref<FakeBlockStore>();
|
||||||
auto askPassword = [] {return "mypassword";};
|
auto askPassword = [] {return "mypassword";};
|
||||||
auto config = CryConfigLoader(mockConsole(), Random::PseudoRandom(), SCrypt::TestSettings, askPassword, askPassword, none)
|
auto config = CryConfigLoader(mockConsole(), Random::PseudoRandom(), SCrypt::TestSettings, askPassword, askPassword, none, true)
|
||||||
.loadOrCreate(configFile.path()).value();
|
.loadOrCreate(configFile.path()).value();
|
||||||
return make_unique_ref<CryDevice>(std::move(config), std::move(blockStore));
|
return make_unique_ref<CryDevice>(std::move(config), std::move(blockStore));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user