Use config file instead of dir for basedir metadata

This commit is contained in:
Sebastian Messmer 2017-09-28 08:19:30 +01:00
parent aace4c2f13
commit 49719e3e66
6 changed files with 76 additions and 72 deletions

View File

@ -198,14 +198,16 @@ namespace cryfs {
}
void Cli::_checkConfigIntegrity(const bf::path& basedir, const CryConfigFile& config) {
if (!BasedirMetadata::filesystemIdForBasedirIsCorrect(basedir, config.config()->FilesystemId())) {
auto basedirMetadata = BasedirMetadata::load();
if (!basedirMetadata.filesystemIdForBasedirIsCorrect(basedir, config.config()->FilesystemId())) {
if (!_console->askYesNo("The filesystem id in the config file is different to the last time we loaded a filesystem from this basedir. This can be genuine if you replaced the filesystem with a different one. If you didn't do that, it is possible that an attacker did. Do you want to continue loading the file system?", false)) {
throw std::runtime_error(
"The filesystem id in the config file is different to the last time we loaded a filesystem from this basedir.");
}
}
// Update local state (or create it if it didn't exist yet)
BasedirMetadata::updateFilesystemIdForBasedir(basedir, config.config()->FilesystemId());
basedirMetadata.updateFilesystemIdForBasedir(basedir, config.config()->FilesystemId());
basedirMetadata.save();
}
CryConfigLoader::ConfigLoadResult Cli::_loadOrCreateConfig(const ProgramOptions &options) {

View File

@ -15,68 +15,57 @@ using std::ostream;
using std::istream;
using std::ifstream;
using std::ofstream;
using std::string;
namespace cryfs {
namespace {
bf::path _localStateConfigFile(const bf::path& basedir) {
std::string basedir_id;
CryptoPP::SHA512 hash;
CryptoPP::StringSource(bf::canonical(basedir).native(), true,
new CryptoPP::HashFilter(hash,
new CryptoPP::HexEncoder(
new CryptoPP::StringSink(basedir_id)
)
)
);
return LocalStateDir::forMapFromBasedirToConfigFiles() / basedir_id;
}
void _serialize(ostream& stream, const CryConfig::FilesystemID& filesystemId) {
ptree pt;
pt.put<std::string>("filesystemId", filesystemId.ToString());
ptree _load(const bf::path &metadataFilePath) {
ptree result;
write_json(stream, pt);
}
CryConfig::FilesystemID _deserialize(istream& stream) {
ptree pt;
read_json(stream, pt);
std::string filesystemId = pt.get<std::string>("filesystemId");
return CryConfig::FilesystemID::FromString(filesystemId);
}
optional<CryConfig::FilesystemID> _load(const bf::path &metadataFilePath) {
ifstream file(metadataFilePath.native());
if (!file.good()) {
// State file doesn't exist
return none;
if (file.good()) {
read_json(file, result);
}
return _deserialize(file);
return result;
}
void _save(const bf::path &metadataFilePath, const CryConfig::FilesystemID& filesystemId) {
void _save(const bf::path &metadataFilePath, const ptree& data) {
ofstream file(metadataFilePath.native(), std::ios::trunc);
_serialize(file, filesystemId);
write_json(file, data);
}
string jsonPathForBasedir(const bf::path &basedir) {
return bf::canonical(basedir).native() + ".filesystemId";
}
}
bool BasedirMetadata::filesystemIdForBasedirIsCorrect(const bf::path &basedir, const CryConfig::FilesystemID &filesystemId) {
auto metadataFile = _localStateConfigFile(basedir);
auto loaded = _load(metadataFile);
if (loaded == none) {
// Local state not known. Possibly the file system is currently being created.
return true;
BasedirMetadata::BasedirMetadata(ptree data)
:_data(std::move(data)) {}
BasedirMetadata BasedirMetadata::load() {
return BasedirMetadata(_load(LocalStateDir::forBasedirMetadata()));
}
void BasedirMetadata::save() {
_save(LocalStateDir::forBasedirMetadata(), _data);
}
bool BasedirMetadata::filesystemIdForBasedirIsCorrect(const bf::path &basedir, const CryConfig::FilesystemID &filesystemId) const {
auto entry = _data.get_optional<string>(jsonPathForBasedir(basedir));
if (entry == boost::none) {
return true; // Basedir not known in local state yet.
}
return loaded == filesystemId;
auto filesystemIdFromState = CryConfig::FilesystemID::FromString(*entry);
return filesystemIdFromState == filesystemId;
}
void BasedirMetadata::updateFilesystemIdForBasedir(const bf::path &basedir, const CryConfig::FilesystemID &filesystemId) {
auto metadataFile = _localStateConfigFile(basedir);
_save(metadataFile, filesystemId);
BasedirMetadata& BasedirMetadata::updateFilesystemIdForBasedir(const bf::path &basedir, const CryConfig::FilesystemID &filesystemId) {
_data.put<string>(jsonPathForBasedir(basedir), filesystemId.ToString());
return *this;
}
}

View File

@ -3,14 +3,28 @@
#define MESSMER_CRYFS_LOCALSTATE_BASEDIRMETADATA_H_
#include <boost/filesystem/path.hpp>
#include <boost/property_tree/ptree.hpp>
#include "../config/CryConfig.h"
namespace cryfs {
class BasedirMetadata final {
public:
static bool filesystemIdForBasedirIsCorrect(const boost::filesystem::path &basedir, const CryConfig::FilesystemID &filesystemId);
static void updateFilesystemIdForBasedir(const boost::filesystem::path &basedir, const CryConfig::FilesystemID &filesystemId);
static BasedirMetadata load();
void save();
BasedirMetadata(const BasedirMetadata&) = delete;
BasedirMetadata& operator=(const BasedirMetadata&) = delete;
BasedirMetadata(BasedirMetadata&&) = default;
BasedirMetadata& operator=(BasedirMetadata&&) = default;
bool filesystemIdForBasedirIsCorrect(const boost::filesystem::path &basedir, const CryConfig::FilesystemID &filesystemId) const;
BasedirMetadata& updateFilesystemIdForBasedir(const boost::filesystem::path &basedir, const CryConfig::FilesystemID &filesystemId);
private:
BasedirMetadata(boost::property_tree::ptree data);
boost::property_tree::ptree _data;
};
}

View File

@ -14,18 +14,17 @@ namespace cryfs {
}
bf::path LocalStateDir::forFilesystemId(const CryConfig::FilesystemID &filesystemId) {
_createDirIfNotExists(appDir());
bf::path filesystems_dir = appDir() / "filesystems";
_createDirIfNotExists(filesystems_dir);
bf::path this_filesystem_dir = filesystems_dir / filesystemId.ToString();
_createDirIfNotExists(this_filesystem_dir);
return this_filesystem_dir;
_createDirIfNotExists(appDir());
bf::path filesystems_dir = appDir() / "filesystems";
_createDirIfNotExists(filesystems_dir);
bf::path this_filesystem_dir = filesystems_dir / filesystemId.ToString();
_createDirIfNotExists(this_filesystem_dir);
return this_filesystem_dir;
}
bf::path LocalStateDir::forMapFromBasedirToConfigFiles() {
bf::path result = appDir() / "map_basedir_initialconfigfile";
_createDirIfNotExists(result);
return result;
bf::path LocalStateDir::forBasedirMetadata() {
_createDirIfNotExists(appDir());
return appDir() / "basedirs";
}
void LocalStateDir::_createDirIfNotExists(const bf::path &path) {

View File

@ -11,7 +11,7 @@ namespace cryfs {
class LocalStateDir final {
public:
static boost::filesystem::path forFilesystemId(const CryConfig::FilesystemID &filesystemId);
static boost::filesystem::path forMapFromBasedirToConfigFiles();
static boost::filesystem::path forBasedirMetadata();
// Use this from test cases to not pollute local config
// TODO Make test cases call this

View File

@ -36,32 +36,32 @@ public:
};
TEST_F(BasedirMetadataTest, givenEmptyState_whenCalled_thenSucceeds) {
EXPECT_TRUE(BasedirMetadata::filesystemIdForBasedirIsCorrect(basedir1, id1));
EXPECT_TRUE(BasedirMetadata::load().filesystemIdForBasedirIsCorrect(basedir1, id1));
}
TEST_F(BasedirMetadataTest, givenStateWithBasedir_whenCalledForDifferentBasedir_thenSucceeds) {
BasedirMetadata::updateFilesystemIdForBasedir(basedir2, id1);
EXPECT_TRUE(BasedirMetadata::filesystemIdForBasedirIsCorrect(basedir1, id1));
BasedirMetadata::load().updateFilesystemIdForBasedir(basedir2, id1).save();
EXPECT_TRUE(BasedirMetadata::load().filesystemIdForBasedirIsCorrect(basedir1, id1));
}
TEST_F(BasedirMetadataTest, givenStateWithBasedir_whenCalledWithSameId_thenSucceeds) {
BasedirMetadata::updateFilesystemIdForBasedir(basedir1, id1);
EXPECT_TRUE(BasedirMetadata::filesystemIdForBasedirIsCorrect(basedir1, id1));
BasedirMetadata::load().updateFilesystemIdForBasedir(basedir1, id1).save();
EXPECT_TRUE(BasedirMetadata::load().filesystemIdForBasedirIsCorrect(basedir1, id1));
}
TEST_F(BasedirMetadataTest, givenStateWithBasedir_whenCalledWithDifferentId_thenFails) {
BasedirMetadata::updateFilesystemIdForBasedir(basedir1, id2);
EXPECT_FALSE(BasedirMetadata::filesystemIdForBasedirIsCorrect(basedir1, id1));
BasedirMetadata::load().updateFilesystemIdForBasedir(basedir1, id2).save();
EXPECT_FALSE(BasedirMetadata::load().filesystemIdForBasedirIsCorrect(basedir1, id1));
}
TEST_F(BasedirMetadataTest, givenStateWithUpdatedBasedir_whenCalledWithSameId_thenSucceeds) {
BasedirMetadata::updateFilesystemIdForBasedir(basedir1, id2);
BasedirMetadata::updateFilesystemIdForBasedir(basedir1, id1);
EXPECT_TRUE(BasedirMetadata::filesystemIdForBasedirIsCorrect(basedir1, id1));
BasedirMetadata::load().updateFilesystemIdForBasedir(basedir1, id2).save();
BasedirMetadata::load().updateFilesystemIdForBasedir(basedir1, id1).save();
EXPECT_TRUE(BasedirMetadata::load().filesystemIdForBasedirIsCorrect(basedir1, id1));
}
TEST_F(BasedirMetadataTest, givenStateWithUpdatedBasedir_whenCalledWithDifferentId_thenFails) {
BasedirMetadata::updateFilesystemIdForBasedir(basedir1, id2);
BasedirMetadata::updateFilesystemIdForBasedir(basedir1, id1);
EXPECT_FALSE(BasedirMetadata::filesystemIdForBasedirIsCorrect(basedir1, id2));
BasedirMetadata::load().updateFilesystemIdForBasedir(basedir1, id2).save();
BasedirMetadata::load().updateFilesystemIdForBasedir(basedir1, id1).save();
EXPECT_FALSE(BasedirMetadata::load().filesystemIdForBasedirIsCorrect(basedir1, id2));
}