Ask before migrating an old CryFS file system to a new version.

This commit is contained in:
Sebastian Messmer 2016-05-03 20:34:30 -07:00
parent 010833e25b
commit 9a0b0a0c36
3 changed files with 72 additions and 9 deletions

View File

@ -28,7 +28,7 @@ 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, const boost::optional<uint32_t> &blocksizeBytesFromCommandLine, bool noninteractive) CryConfigLoader::CryConfigLoader(shared_ptr<Console> console, RandomGenerator &keyGenerator, const SCryptSettings &scryptSettings, function<string()> askPasswordForExistingFilesystem, function<string()> askPasswordForNewFilesystem, const optional<string> &cipherFromCommandLine, const boost::optional<uint32_t> &blocksizeBytesFromCommandLine, bool noninteractive)
: _creator(std::move(console), keyGenerator, noninteractive), _scryptSettings(scryptSettings), : _console(console), _creator(console, keyGenerator, noninteractive), _scryptSettings(scryptSettings),
_askPasswordForExistingFilesystem(askPasswordForExistingFilesystem), _askPasswordForNewFilesystem(askPasswordForNewFilesystem), _askPasswordForExistingFilesystem(askPasswordForExistingFilesystem), _askPasswordForNewFilesystem(askPasswordForNewFilesystem),
_cipherFromCommandLine(cipherFromCommandLine), _blocksizeBytesFromCommandLine(blocksizeBytesFromCommandLine) { _cipherFromCommandLine(cipherFromCommandLine), _blocksizeBytesFromCommandLine(blocksizeBytesFromCommandLine) {
} }
@ -57,12 +57,13 @@ optional<CryConfigFile> CryConfigLoader::_loadConfig(const bf::path &filename) {
} }
void CryConfigLoader::_checkVersion(const CryConfig &config) { void CryConfigLoader::_checkVersion(const CryConfig &config) {
const string allowedVersionPrefix = string() + gitversion::MajorVersion() + "." + gitversion::MinorVersion() + ".";
if (!boost::starts_with(config.Version(), allowedVersionPrefix)) {
throw std::runtime_error(string() + "This filesystem was created with CryFS " + config.Version() + " and is incompatible. Please create a new one with your version of CryFS and migrate your data.");
}
if (gitversion::VersionCompare::isOlderThan(gitversion::VersionString(), config.Version())) { if (gitversion::VersionCompare::isOlderThan(gitversion::VersionString(), config.Version())) {
throw std::runtime_error(string() + "This filesystem was used with CryFS " + config.Version() + " and should not be opened with older versions anymore. Please update your CryFS version."); throw std::runtime_error(string() + "This filesystem is for CryFS " + config.Version() + " and should not be opened with older versions. Please update your CryFS version.");
}
if (gitversion::VersionCompare::isOlderThan(config.Version(), gitversion::VersionString())) {
if (!_console->askYesNo("This filesystem is for CryFS " + config.Version() + ". It can be migrated to CryFS " + gitversion::VersionString() + ", but afterwards couldn't be opened anymore with older versions. Do you want to migrate it?")) {
throw std::runtime_error(string() + "Not migrating file system.");
}
} }
} }

View File

@ -21,9 +21,10 @@ public:
private: private:
boost::optional<CryConfigFile> _loadConfig(const boost::filesystem::path &filename); boost::optional<CryConfigFile> _loadConfig(const boost::filesystem::path &filename);
CryConfigFile _createConfig(const boost::filesystem::path &filename); CryConfigFile _createConfig(const boost::filesystem::path &filename);
static void _checkVersion(const CryConfig &config); void _checkVersion(const CryConfig &config);
void _checkCipher(const CryConfig &config) const; void _checkCipher(const CryConfig &config) const;
std::shared_ptr<cpputils::Console> _console;
CryConfigCreator _creator; CryConfigCreator _creator;
cpputils::SCryptSettings _scryptSettings; cpputils::SCryptSettings _scryptSettings;
std::function<std::string()> _askPasswordForExistingFilesystem; std::function<std::string()> _askPasswordForExistingFilesystem;

View File

@ -5,6 +5,7 @@
#include <cpp-utils/random/Random.h> #include <cpp-utils/random/Random.h>
#include <cpp-utils/crypto/symmetric/ciphers.h> #include <cpp-utils/crypto/symmetric/ciphers.h>
#include <gitversion/gitversion.h> #include <gitversion/gitversion.h>
#include <gitversion/VersionCompare.h>
using cpputils::unique_ref; using cpputils::unique_ref;
using cpputils::make_unique_ref; using cpputils::make_unique_ref;
@ -16,6 +17,7 @@ using std::string;
using std::ostream; using std::ostream;
using ::testing::Return; using ::testing::Return;
using ::testing::_; using ::testing::_;
using ::testing::HasSubstr;
using namespace cryfs; using namespace cryfs;
@ -29,11 +31,13 @@ namespace boost {
class CryConfigLoaderTest: public ::testing::Test, public TestWithMockConsole { class CryConfigLoaderTest: public ::testing::Test, public TestWithMockConsole {
public: public:
CryConfigLoaderTest(): file(false) {} CryConfigLoaderTest(): file(false) {
console = mockConsole();
}
CryConfigLoader loader(const string &password, bool noninteractive, 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, none, noninteractive); return CryConfigLoader(console, cpputils::Random::PseudoRandom(), SCrypt::TestSettings, askPassword, askPassword, cipher, none, noninteractive);
} }
CryConfigFile Create(const string &password = "mypassword", const optional<string> &cipher = none, bool noninteractive = false) { CryConfigFile Create(const string &password = "mypassword", const optional<string> &cipher = none, bool noninteractive = false) {
@ -71,6 +75,24 @@ public:
cfg.save(); cfg.save();
} }
string olderVersion() {
string olderVersion;
if (std::stol(gitversion::MinorVersion()) > 0) {
olderVersion = gitversion::MajorVersion() + "." + std::to_string(std::stol(gitversion::MinorVersion()) - 1);
} else {
olderVersion = std::to_string(std::stol(gitversion::MajorVersion()) - 1) + "." + gitversion::MinorVersion();
}
assert(gitversion::VersionCompare::isOlderThan(olderVersion, gitversion::VersionString()));
return olderVersion;
}
string newerVersion() {
string newerVersion = gitversion::MajorVersion()+"."+std::to_string(std::stol(gitversion::MinorVersion())+1);
assert(gitversion::VersionCompare::isOlderThan(gitversion::VersionString(), newerVersion));
return newerVersion;
}
std::shared_ptr<MockConsole> console;
TempFile file; TempFile file;
}; };
@ -176,3 +198,42 @@ TEST_F(CryConfigLoaderTest, Version_Create) {
EXPECT_EQ(gitversion::VersionString(), created.config()->Version()); EXPECT_EQ(gitversion::VersionString(), created.config()->Version());
EXPECT_EQ(gitversion::VersionString(), created.config()->CreatedWithVersion()); EXPECT_EQ(gitversion::VersionString(), created.config()->CreatedWithVersion());
} }
TEST_F(CryConfigLoaderTest, RefusesToLoadNewerFilesystem) {
string version = newerVersion();
CreateWithVersion(version);
try {
Load();
EXPECT_TRUE(false); // expect throw
} catch (const std::runtime_error &e) {
EXPECT_THAT(e.what(), HasSubstr("Please update your CryFS version"));
}
}
TEST_F(CryConfigLoaderTest, AsksWhenMigratingOlderFilesystem) {
EXPECT_CALL(*console, askYesNo(HasSubstr("Do you want to migrate it?"))).Times(1).WillOnce(Return(true));
string version = olderVersion();
CreateWithVersion(version);
EXPECT_NE(boost::none, Load());
}
TEST_F(CryConfigLoaderTest, DoesNotAskForMigrationWhenCorrectVersion) {
EXPECT_CALL(*console, askYesNo(HasSubstr("Do you want to migrate it?"))).Times(0);
CreateWithVersion(gitversion::VersionString());
EXPECT_NE(boost::none, Load());
}
TEST_F(CryConfigLoaderTest, DontMigrateWhenAnsweredNo) {
EXPECT_CALL(*console, askYesNo(HasSubstr("Do you want to migrate it?"))).Times(1).WillOnce(Return(false));
string version = olderVersion();
CreateWithVersion(version);
try {
Load();
EXPECT_TRUE(false); // expect throw
} catch (const std::runtime_error &e) {
EXPECT_THAT(e.what(), HasSubstr("Not migrating file system"));
}
}