Add environment variable to specify local storage directory

This commit is contained in:
Sebastian Messmer 2018-04-21 22:04:21 -07:00
parent b0077e7a81
commit d7a41089ba
22 changed files with 161 additions and 87 deletions

View File

@ -192,8 +192,8 @@ namespace cryfs {
return *configFile;
}
void Cli::_checkConfigIntegrity(const bf::path& basedir, const CryConfigFile& config, bool allowReplacedFilesystem) {
auto basedirMetadata = BasedirMetadata::load();
void Cli::_checkConfigIntegrity(const bf::path& basedir, const LocalStateDir& localStateDir, const CryConfigFile& config, bool allowReplacedFilesystem) {
auto basedirMetadata = BasedirMetadata::load(localStateDir);
if (!allowReplacedFilesystem && !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 CryfsException(
@ -205,24 +205,24 @@ namespace cryfs {
basedirMetadata.save();
}
CryConfigLoader::ConfigLoadResult Cli::_loadOrCreateConfig(const ProgramOptions &options) {
CryConfigLoader::ConfigLoadResult Cli::_loadOrCreateConfig(const ProgramOptions &options, const LocalStateDir& localStateDir) {
auto configFile = _determineConfigFile(options);
auto config = _loadOrCreateConfigFile(std::move(configFile), options.cipher(), options.blocksizeBytes(), options.allowFilesystemUpgrade(), options.missingBlockIsIntegrityViolation(), options.allowReplacedFilesystem());
auto config = _loadOrCreateConfigFile(std::move(configFile), localStateDir, options.cipher(), options.blocksizeBytes(), options.allowFilesystemUpgrade(), options.missingBlockIsIntegrityViolation(), options.allowReplacedFilesystem());
if (config == none) {
throw CryfsException("Could not load config file. Did you enter the correct password?", ErrorCode::WrongPassword);
}
_checkConfigIntegrity(options.baseDir(), config->configFile, options.allowReplacedFilesystem());
_checkConfigIntegrity(options.baseDir(), localStateDir, config->configFile, options.allowReplacedFilesystem());
return std::move(*config);
}
optional<CryConfigLoader::ConfigLoadResult> Cli::_loadOrCreateConfigFile(bf::path configFilePath, const optional<string> &cipher, const optional<uint32_t> &blocksizeBytes, bool allowFilesystemUpgrade, const optional<bool> &missingBlockIsIntegrityViolation, bool allowReplacedFilesystem) {
optional<CryConfigLoader::ConfigLoadResult> Cli::_loadOrCreateConfigFile(bf::path configFilePath, LocalStateDir localStateDir, const optional<string> &cipher, const optional<uint32_t> &blocksizeBytes, bool allowFilesystemUpgrade, const optional<bool> &missingBlockIsIntegrityViolation, bool allowReplacedFilesystem) {
if (_noninteractive) {
return CryConfigLoader(_console, _keyGenerator, _scryptSettings,
return CryConfigLoader(_console, _keyGenerator, std::move(localStateDir), _scryptSettings,
&Cli::_askPasswordNoninteractive,
&Cli::_askPasswordNoninteractive,
cipher, blocksizeBytes, missingBlockIsIntegrityViolation).loadOrCreate(std::move(configFilePath), allowFilesystemUpgrade, allowReplacedFilesystem);
} else {
return CryConfigLoader(_console, _keyGenerator, _scryptSettings,
return CryConfigLoader(_console, _keyGenerator, std::move(localStateDir), _scryptSettings,
&Cli::_askPasswordForExistingFilesystem,
&Cli::_askPasswordForNewFilesystem,
cipher, blocksizeBytes, missingBlockIsIntegrityViolation).loadOrCreate(std::move(configFilePath), allowFilesystemUpgrade, allowReplacedFilesystem);
@ -231,9 +231,10 @@ namespace cryfs {
void Cli::_runFilesystem(const ProgramOptions &options) {
try {
LocalStateDir localStateDir(Environment::localStateDir());
auto blockStore = make_unique_ref<OnDiskBlockStore2>(options.baseDir());
auto config = _loadOrCreateConfig(options);
CryDevice device(std::move(config.configFile), std::move(blockStore), config.myClientId,
auto config = _loadOrCreateConfig(options, localStateDir);
CryDevice device(std::move(config.configFile), std::move(blockStore), std::move(localStateDir), config.myClientId,
options.noIntegrityChecks(), config.configFile.config()->missingBlockIsIntegrityViolation());
_sanityCheckFilesystem(&device);
fspp::FilesystemImpl fsimpl(&device);

View File

@ -23,9 +23,9 @@ namespace cryfs {
private:
void _checkForUpdates(cpputils::unique_ref<cpputils::HttpClient> httpClient);
void _runFilesystem(const program_options::ProgramOptions &options);
CryConfigLoader::ConfigLoadResult _loadOrCreateConfig(const program_options::ProgramOptions &options);
void _checkConfigIntegrity(const boost::filesystem::path& basedir, const CryConfigFile& config, bool allowReplacedFilesystem);
boost::optional<CryConfigLoader::ConfigLoadResult> _loadOrCreateConfigFile(boost::filesystem::path configFilePath, const boost::optional<std::string> &cipher, const boost::optional<uint32_t> &blocksizeBytes, bool allowFilesystemUpgrade, const boost::optional<bool> &missingBlockIsIntegrityViolation, bool allowReplacedFilesystem);
CryConfigLoader::ConfigLoadResult _loadOrCreateConfig(const program_options::ProgramOptions &options, const LocalStateDir& localStateDir);
void _checkConfigIntegrity(const boost::filesystem::path& basedir, const LocalStateDir& localStateDir, const CryConfigFile& config, bool allowReplacedFilesystem);
boost::optional<CryConfigLoader::ConfigLoadResult> _loadOrCreateConfigFile(boost::filesystem::path configFilePath, LocalStateDir localStateDir, const boost::optional<std::string> &cipher, const boost::optional<uint32_t> &blocksizeBytes, bool allowFilesystemUpgrade, const boost::optional<bool> &missingBlockIsIntegrityViolation, bool allowReplacedFilesystem);
boost::filesystem::path _determineConfigFile(const program_options::ProgramOptions &options);
static std::string _askPasswordForExistingFilesystem();
static std::string _askPasswordForNewFilesystem();

View File

@ -1,12 +1,16 @@
#include "Environment.h"
#include <cstdlib>
#include <cpp-utils/system/homedir.h>
#include <boost/filesystem.hpp>
using std::string;
namespace bf = boost::filesystem;
namespace cryfs {
const string Environment::FRONTEND_KEY = "CRYFS_FRONTEND";
const string Environment::FRONTEND_NONINTERACTIVE = "noninteractive";
const string Environment::NOUPDATECHECK_KEY = "CRYFS_NO_UPDATE_CHECK";
const string Environment::LOCALSTATEDIR_KEY = "CRYFS_LOCAL_STATE_DIR";
bool Environment::isNoninteractive() {
char *frontend = std::getenv(FRONTEND_KEY.c_str());
@ -16,4 +20,19 @@ namespace cryfs {
bool Environment::noUpdateCheck() {
return nullptr != std::getenv(NOUPDATECHECK_KEY.c_str());
}
const bf::path& Environment::defaultLocalStateDir() {
static const bf::path value = cpputils::system::HomeDirectory::get() / ".cryfs";
return value;
}
bf::path Environment::localStateDir() {
const char* localStateDir = std::getenv(LOCALSTATEDIR_KEY.c_str());
if (nullptr == localStateDir) {
return defaultLocalStateDir();
}
return bf::absolute(localStateDir);
}
}

View File

@ -3,6 +3,7 @@
#define MESSMER_CRYFS_CLI_ENVIRONMENT_H
#include <string>
#include <boost/filesystem/path.hpp>
namespace cryfs {
@ -10,10 +11,13 @@ namespace cryfs {
public:
static bool isNoninteractive();
static bool noUpdateCheck();
static boost::filesystem::path localStateDir();
static const boost::filesystem::path& defaultLocalStateDir();
static const std::string FRONTEND_KEY;
static const std::string FRONTEND_NONINTERACTIVE;
static const std::string NOUPDATECHECK_KEY;
static const std::string LOCALSTATEDIR_KEY;
private:
Environment() = delete;

View File

@ -210,6 +210,11 @@ void Parser::_showHelp() {
<< " " << Environment::NOUPDATECHECK_KEY << "=true\n"
<< "\tBy default, CryFS connects to the internet to check for known\n"
<< "\tsecurity vulnerabilities and new versions. This option disables this.\n"
<< " " << Environment::LOCALSTATEDIR_KEY << "=[path]\n"
<< "\tSets the directory cryfs uses to store local state. This local state\n"
<< "\tis used to recognize known file systems and run integrity checks\n"
<< "\t(i.e. check that they haven't been modified by an attacker.\n"
<< "\tDefault value: " << Environment::defaultLocalStateDir().c_str() << "\n"
<< endl;
}

View File

@ -15,8 +15,8 @@ using boost::none;
namespace cryfs {
CryConfigCreator::CryConfigCreator(shared_ptr<Console> console, RandomGenerator &encryptionKeyGenerator)
:_console(console), _configConsole(console), _encryptionKeyGenerator(encryptionKeyGenerator) {
CryConfigCreator::CryConfigCreator(shared_ptr<Console> console, RandomGenerator &encryptionKeyGenerator, LocalStateDir localStateDir)
:_console(console), _configConsole(console), _encryptionKeyGenerator(encryptionKeyGenerator), _localStateDir(std::move(localStateDir)) {
}
CryConfigCreator::ConfigCreateResult CryConfigCreator::create(const optional<string> &cipherFromCommandLine, const optional<uint32_t> &blocksizeBytesFromCommandLine, const optional<bool> &missingBlockIsIntegrityViolationFromCommandLine, bool allowReplacedFilesystem) {
@ -29,7 +29,7 @@ namespace cryfs {
config.SetRootBlob(_generateRootBlobId());
config.SetFilesystemId(_generateFilesystemID());
auto encryptionKey = _generateEncKey(config.Cipher());
auto localState = LocalStateMetadata::loadOrGenerate(LocalStateDir::forFilesystemId(config.FilesystemId()), cpputils::Data::FromString(encryptionKey), allowReplacedFilesystem);
auto localState = LocalStateMetadata::loadOrGenerate(_localStateDir.forFilesystemId(config.FilesystemId()), cpputils::Data::FromString(encryptionKey), allowReplacedFilesystem);
uint32_t myClientId = localState.myClientId();
config.SetEncryptionKey(std::move(encryptionKey));
config.SetExclusiveClientId(_generateExclusiveClientId(missingBlockIsIntegrityViolationFromCommandLine, myClientId));

View File

@ -5,13 +5,14 @@
#include <cpp-utils/pointer/unique_ref.h>
#include <cpp-utils/random/RandomGenerator.h>
#include <cpp-utils/io/Console.h>
#include <cryfs/localstate/LocalStateDir.h>
#include "CryConfig.h"
#include "CryConfigConsole.h"
namespace cryfs {
class CryConfigCreator final {
public:
CryConfigCreator(std::shared_ptr<cpputils::Console> console, cpputils::RandomGenerator &encryptionKeyGenerator);
CryConfigCreator(std::shared_ptr<cpputils::Console> console, cpputils::RandomGenerator &encryptionKeyGenerator, LocalStateDir localStateDir);
CryConfigCreator(CryConfigCreator &&rhs) = default;
struct ConfigCreateResult {
@ -32,6 +33,7 @@ namespace cryfs {
std::shared_ptr<cpputils::Console> _console;
CryConfigConsole _configConsole;
cpputils::RandomGenerator &_encryptionKeyGenerator;
LocalStateDir _localStateDir;
DISALLOW_COPY_AND_ASSIGN(CryConfigCreator);
};

View File

@ -25,11 +25,12 @@ using namespace cpputils::logging;
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, const boost::optional<bool> &missingBlockIsIntegrityViolationFromCommandLine)
: _console(console), _creator(std::move(console), keyGenerator), _scryptSettings(scryptSettings),
CryConfigLoader::CryConfigLoader(shared_ptr<Console> console, RandomGenerator &keyGenerator, LocalStateDir localStateDir, const SCryptSettings &scryptSettings, function<string()> askPasswordForExistingFilesystem, function<string()> askPasswordForNewFilesystem, const optional<string> &cipherFromCommandLine, const boost::optional<uint32_t> &blocksizeBytesFromCommandLine, const boost::optional<bool> &missingBlockIsIntegrityViolationFromCommandLine)
: _console(console), _creator(std::move(console), keyGenerator, localStateDir), _scryptSettings(scryptSettings),
_askPasswordForExistingFilesystem(askPasswordForExistingFilesystem), _askPasswordForNewFilesystem(askPasswordForNewFilesystem),
_cipherFromCommandLine(cipherFromCommandLine), _blocksizeBytesFromCommandLine(blocksizeBytesFromCommandLine),
_missingBlockIsIntegrityViolationFromCommandLine(missingBlockIsIntegrityViolationFromCommandLine) {
_missingBlockIsIntegrityViolationFromCommandLine(missingBlockIsIntegrityViolationFromCommandLine),
_localStateDir(std::move(localStateDir)) {
}
optional<CryConfigLoader::ConfigLoadResult> CryConfigLoader::_loadConfig(bf::path filename, bool allowFilesystemUpgrade, bool allowReplacedFilesystem) {
@ -62,7 +63,7 @@ optional<CryConfigLoader::ConfigLoadResult> CryConfigLoader::_loadConfig(bf::pat
config->save();
}
_checkCipher(*config->config());
auto localState = LocalStateMetadata::loadOrGenerate(LocalStateDir::forFilesystemId(config->config()->FilesystemId()), cpputils::Data::FromString(config->config()->EncryptionKey()), allowReplacedFilesystem);
auto localState = LocalStateMetadata::loadOrGenerate(_localStateDir.forFilesystemId(config->config()->FilesystemId()), cpputils::Data::FromString(config->config()->EncryptionKey()), allowReplacedFilesystem);
uint32_t myClientId = localState.myClientId();
_checkMissingBlocksAreIntegrityViolations(&*config, myClientId);
return ConfigLoadResult {std::move(*config), myClientId};

View File

@ -13,7 +13,7 @@ namespace cryfs {
class CryConfigLoader final {
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, const boost::optional<uint32_t> &blocksizeBytesFromCommandLine, const boost::optional<bool> &missingBlockIsIntegrityViolationFromCommandLine);
CryConfigLoader(std::shared_ptr<cpputils::Console> console, cpputils::RandomGenerator &keyGenerator, LocalStateDir localStateDir, const cpputils::SCryptSettings &scryptSettings, std::function<std::string()> askPasswordForExistingFilesystem, std::function<std::string()> askPasswordForNewFilesystem, const boost::optional<std::string> &cipherFromCommandLine, const boost::optional<uint32_t> &blocksizeBytesFromCommandLine, const boost::optional<bool> &missingBlockIsIntegrityViolationFromCommandLine);
CryConfigLoader(CryConfigLoader &&rhs) = default;
struct ConfigLoadResult {
@ -38,6 +38,7 @@ private:
boost::optional<std::string> _cipherFromCommandLine;
boost::optional<uint32_t> _blocksizeBytesFromCommandLine;
boost::optional<bool> _missingBlockIsIntegrityViolationFromCommandLine;
LocalStateDir _localStateDir;
DISALLOW_COPY_AND_ASSIGN(CryConfigLoader);
};

View File

@ -51,14 +51,14 @@ namespace bf = boost::filesystem;
namespace cryfs {
CryDevice::CryDevice(CryConfigFile configFile, unique_ref<BlockStore2> blockStore, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation)
: _fsBlobStore(CreateFsBlobStore(std::move(blockStore), &configFile, myClientId, noIntegrityChecks, missingBlockIsIntegrityViolation)),
CryDevice::CryDevice(CryConfigFile configFile, unique_ref<BlockStore2> blockStore, const LocalStateDir& localStateDir, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation)
: _fsBlobStore(CreateFsBlobStore(std::move(blockStore), &configFile, localStateDir, myClientId, noIntegrityChecks, missingBlockIsIntegrityViolation)),
_rootBlobId(GetOrCreateRootBlobId(&configFile)),
_onFsAction() {
}
unique_ref<parallelaccessfsblobstore::ParallelAccessFsBlobStore> CryDevice::CreateFsBlobStore(unique_ref<BlockStore2> blockStore, CryConfigFile *configFile, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation) {
auto blobStore = CreateBlobStore(std::move(blockStore), configFile, myClientId, noIntegrityChecks, missingBlockIsIntegrityViolation);
unique_ref<parallelaccessfsblobstore::ParallelAccessFsBlobStore> CryDevice::CreateFsBlobStore(unique_ref<BlockStore2> blockStore, CryConfigFile *configFile, const LocalStateDir& localStateDir, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation) {
auto blobStore = CreateBlobStore(std::move(blockStore), localStateDir, configFile, myClientId, noIntegrityChecks, missingBlockIsIntegrityViolation);
#ifndef CRYFS_NO_COMPATIBILITY
auto fsBlobStore = MigrateOrCreateFsBlobStore(std::move(blobStore), configFile);
@ -83,8 +83,8 @@ unique_ref<fsblobstore::FsBlobStore> CryDevice::MigrateOrCreateFsBlobStore(uniqu
}
#endif
unique_ref<blobstore::BlobStore> CryDevice::CreateBlobStore(unique_ref<BlockStore2> blockStore, CryConfigFile *configFile, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation) {
auto integrityEncryptedBlockStore = CreateIntegrityEncryptedBlockStore(std::move(blockStore), configFile, myClientId, noIntegrityChecks, missingBlockIsIntegrityViolation);
unique_ref<blobstore::BlobStore> CryDevice::CreateBlobStore(unique_ref<BlockStore2> blockStore, const LocalStateDir& localStateDir, CryConfigFile *configFile, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation) {
auto integrityEncryptedBlockStore = CreateIntegrityEncryptedBlockStore(std::move(blockStore), localStateDir, configFile, myClientId, noIntegrityChecks, missingBlockIsIntegrityViolation);
// Create integrityEncryptedBlockStore not in the same line as BlobStoreOnBlocks, because it can modify BlocksizeBytes
// in the configFile and therefore has to be run before the second parameter to the BlobStoreOnBlocks parameter is evaluated.
return make_unique_ref<BlobStoreOnBlocks>(
@ -96,9 +96,9 @@ unique_ref<blobstore::BlobStore> CryDevice::CreateBlobStore(unique_ref<BlockStor
configFile->config()->BlocksizeBytes());
}
unique_ref<BlockStore2> CryDevice::CreateIntegrityEncryptedBlockStore(unique_ref<BlockStore2> blockStore, CryConfigFile *configFile, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation) {
unique_ref<BlockStore2> CryDevice::CreateIntegrityEncryptedBlockStore(unique_ref<BlockStore2> blockStore, const LocalStateDir& localStateDir, CryConfigFile *configFile, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation) {
auto encryptedBlockStore = CreateEncryptedBlockStore(*configFile->config(), std::move(blockStore));
auto statePath = LocalStateDir::forFilesystemId(configFile->config()->FilesystemId());
auto statePath = localStateDir.forFilesystemId(configFile->config()->FilesystemId());
auto integrityFilePath = statePath / "integritydata";
#ifndef CRYFS_NO_COMPATIBILITY

View File

@ -8,6 +8,7 @@
#include <boost/filesystem.hpp>
#include <fspp/fs_interface/Device.h>
#include <cryfs/localstate/LocalStateDir.h>
#include "parallelaccessfsblobstore/ParallelAccessFsBlobStore.h"
#include "parallelaccessfsblobstore/DirBlobRef.h"
@ -18,7 +19,7 @@ namespace cryfs {
class CryDevice final: public fspp::Device {
public:
CryDevice(CryConfigFile config, cpputils::unique_ref<blockstore::BlockStore2> blockStore, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation);
CryDevice(CryConfigFile config, cpputils::unique_ref<blockstore::BlockStore2> blockStore, const LocalStateDir& localStateDir, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation);
void statfs(const boost::filesystem::path &path, struct ::statvfs *fsstat) override;
@ -53,12 +54,12 @@ private:
blockstore::BlockId GetOrCreateRootBlobId(CryConfigFile *config);
blockstore::BlockId CreateRootBlobAndReturnId();
static cpputils::unique_ref<parallelaccessfsblobstore::ParallelAccessFsBlobStore> CreateFsBlobStore(cpputils::unique_ref<blockstore::BlockStore2> blockStore, CryConfigFile *configFile, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation);
static cpputils::unique_ref<parallelaccessfsblobstore::ParallelAccessFsBlobStore> CreateFsBlobStore(cpputils::unique_ref<blockstore::BlockStore2> blockStore, CryConfigFile *configFile, const LocalStateDir& localStateDir, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation);
#ifndef CRYFS_NO_COMPATIBILITY
static cpputils::unique_ref<fsblobstore::FsBlobStore> MigrateOrCreateFsBlobStore(cpputils::unique_ref<blobstore::BlobStore> blobStore, CryConfigFile *configFile);
#endif
static cpputils::unique_ref<blobstore::BlobStore> CreateBlobStore(cpputils::unique_ref<blockstore::BlockStore2> blockStore, CryConfigFile *configFile, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation);
static cpputils::unique_ref<blockstore::BlockStore2> CreateIntegrityEncryptedBlockStore(cpputils::unique_ref<blockstore::BlockStore2> blockStore, CryConfigFile *configFile, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation);
static cpputils::unique_ref<blobstore::BlobStore> CreateBlobStore(cpputils::unique_ref<blockstore::BlockStore2> blockStore, const LocalStateDir& localStateDir, CryConfigFile *configFile, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation);
static cpputils::unique_ref<blockstore::BlockStore2> CreateIntegrityEncryptedBlockStore(cpputils::unique_ref<blockstore::BlockStore2> blockStore, const LocalStateDir& localStateDir, CryConfigFile *configFile, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation);
static cpputils::unique_ref<blockstore::BlockStore2> CreateEncryptedBlockStore(const CryConfig &config, cpputils::unique_ref<blockstore::BlockStore2> baseBlockStore);
struct BlobWithParent {

View File

@ -42,15 +42,17 @@ string jsonPathForBasedir(const bf::path &basedir) {
}
BasedirMetadata::BasedirMetadata(ptree data)
:_data(data) {}
BasedirMetadata::BasedirMetadata(ptree data, bf::path filename)
:_filename(std::move(filename)), _data(std::move(data)) {}
BasedirMetadata BasedirMetadata::load() {
return BasedirMetadata(_load(LocalStateDir::forBasedirMetadata()));
BasedirMetadata BasedirMetadata::load(const LocalStateDir& localStateDir) {
auto filename = localStateDir.forBasedirMetadata();
auto loaded = _load(filename);
return BasedirMetadata(std::move(loaded), std::move(filename));
}
void BasedirMetadata::save() {
_save(LocalStateDir::forBasedirMetadata(), _data);
_save(_filename, _data);
}
bool BasedirMetadata::filesystemIdForBasedirIsCorrect(const bf::path &basedir, const CryConfig::FilesystemID &filesystemId) const {

View File

@ -5,12 +5,13 @@
#include <boost/filesystem/path.hpp>
#include <boost/property_tree/ptree.hpp>
#include "../config/CryConfig.h"
#include "LocalStateDir.h"
namespace cryfs {
class BasedirMetadata final {
public:
static BasedirMetadata load();
static BasedirMetadata load(const LocalStateDir& localStateDir);
void save();
BasedirMetadata(const BasedirMetadata&) = delete;
@ -22,8 +23,9 @@ public:
BasedirMetadata& updateFilesystemIdForBasedir(const boost::filesystem::path &basedir, const CryConfig::FilesystemID &filesystemId);
private:
BasedirMetadata(boost::property_tree::ptree data);
BasedirMetadata(boost::property_tree::ptree data, boost::filesystem::path filename);
boost::filesystem::path _filename;
boost::property_tree::ptree _data;
};

View File

@ -1,28 +1,23 @@
#include "LocalStateDir.h"
#include <cpp-utils/system/homedir.h>
#include <boost/filesystem.hpp>
namespace bf = boost::filesystem;
namespace cryfs {
namespace {
bf::path appDir() {
return cpputils::system::HomeDirectory::get() / ".cryfs";
}
}
LocalStateDir::LocalStateDir(bf::path appDir): _appDir(std::move(appDir)) {}
bf::path LocalStateDir::forFilesystemId(const CryConfig::FilesystemID &filesystemId) {
_createDirIfNotExists(appDir());
bf::path filesystems_dir = appDir() / "filesystems";
bf::path LocalStateDir::forFilesystemId(const CryConfig::FilesystemID &filesystemId) const {
_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::forBasedirMetadata() {
_createDirIfNotExists(appDir());
return appDir() / "basedirs";
bf::path LocalStateDir::forBasedirMetadata() const {
_createDirIfNotExists(_appDir);
return _appDir / "basedirs";
}
void LocalStateDir::_createDirIfNotExists(const bf::path &path) {

View File

@ -10,11 +10,13 @@ namespace cryfs {
class LocalStateDir final {
public:
static boost::filesystem::path forFilesystemId(const CryConfig::FilesystemID &filesystemId);
static boost::filesystem::path forBasedirMetadata();
LocalStateDir(boost::filesystem::path appDir);
boost::filesystem::path forFilesystemId(const CryConfig::FilesystemID &filesystemId) const;
boost::filesystem::path forBasedirMetadata() const;
private:
LocalStateDir(); // static functions only
boost::filesystem::path _appDir;
static void _createDirIfNotExists(const boost::filesystem::path &path);
};

View File

@ -1,12 +1,15 @@
#include <gtest/gtest.h>
#include <cryfs-cli/Environment.h>
#include <boost/optional.hpp>
#include <boost/filesystem.hpp>
using namespace cryfs;
using std::string;
using boost::optional;
using boost::none;
namespace bf = boost::filesystem;
class EnvironmentTest : public ::testing::Test {
public:
// WithEnv sets an environment variable while it is in scope.
@ -62,3 +65,22 @@ TEST_F(EnvironmentTest, NoUpdateCheck_SetToOtherValue) {
// No matter what the value is, setting the environment variable says we don't do update checks.
EXPECT_TRUE(Environment::noUpdateCheck());
}
TEST_F(EnvironmentTest, LocalStateDir_NotSet) {
EXPECT_EQ(Environment::defaultLocalStateDir(), Environment::localStateDir());
}
TEST_F(EnvironmentTest, LocalStateDir_Set) {
WithEnv env("CRYFS_LOCAL_STATE_DIR", "/my/local/state/dir");
EXPECT_EQ("/my/local/state/dir", Environment::localStateDir().native());
}
TEST_F(EnvironmentTest, LocalStateDir_ConvertsRelativeToAbsolutePath_WithDot) {
WithEnv env("CRYFS_LOCAL_STATE_DIR", "./dir");
EXPECT_EQ((bf::current_path() / "./dir").native(), Environment::localStateDir().native());
}
TEST_F(EnvironmentTest, LocalStateDir_ConvertsRelativeToAbsolutePath_WithoutDot) {
WithEnv env("CRYFS_LOCAL_STATE_DIR", "dir");
EXPECT_EQ((bf::current_path() / "dir").native(), Environment::localStateDir().native());
}

View File

@ -7,6 +7,7 @@
#include "../testutils/TestWithFakeHomeDirectory.h"
#include <cpp-utils/io/NoninteractiveConsole.h>
#include <gitversion/gitversion.h>
#include <cryfs/localstate/LocalStateDir.h>
using namespace cryfs;
@ -43,12 +44,15 @@ class CryConfigCreatorTest: public ::testing::Test, TestWithFakeHomeDirectory {
public:
CryConfigCreatorTest()
: console(make_shared<MockConsole>()),
creator(console, cpputils::Random::PseudoRandom()),
noninteractiveCreator(make_shared<NoninteractiveConsole>(console), cpputils::Random::PseudoRandom()) {
tempLocalStateDir(), localStateDir(tempLocalStateDir.path()),
creator(console, cpputils::Random::PseudoRandom(), localStateDir),
noninteractiveCreator(make_shared<NoninteractiveConsole>(console), cpputils::Random::PseudoRandom(), localStateDir) {
EXPECT_CALL(*console, ask(HasSubstr("block cipher"), _)).WillRepeatedly(ChooseAnyCipher());
EXPECT_CALL(*console, ask(HasSubstr("block size"), _)).WillRepeatedly(Return(0));
}
shared_ptr<MockConsole> console;
cpputils::TempDir tempLocalStateDir;
LocalStateDir localStateDir;
CryConfigCreator creator;
CryConfigCreator noninteractiveCreator;

View File

@ -56,17 +56,17 @@ private:
class CryConfigLoaderTest: public ::testing::Test, public TestWithMockConsole, TestWithFakeHomeDirectory {
public:
CryConfigLoaderTest(): file(false) {
CryConfigLoaderTest(): file(false), tempLocalStateDir(), localStateDir(tempLocalStateDir.path()) {
console = mockConsole();
}
CryConfigLoader loader(const string &password, bool noninteractive, const optional<string> &cipher = none) {
auto askPassword = [password] { return password;};
if(noninteractive) {
return CryConfigLoader(make_shared<NoninteractiveConsole>(console), cpputils::Random::PseudoRandom(), SCrypt::TestSettings, askPassword,
return CryConfigLoader(make_shared<NoninteractiveConsole>(console), cpputils::Random::PseudoRandom(), localStateDir, SCrypt::TestSettings, askPassword,
askPassword, cipher, none, none);
} else {
return CryConfigLoader(console, cpputils::Random::PseudoRandom(), SCrypt::TestSettings, askPassword,
return CryConfigLoader(console, cpputils::Random::PseudoRandom(), localStateDir, SCrypt::TestSettings, askPassword,
askPassword, cipher, none, none);
}
}
@ -100,7 +100,7 @@ public:
void CreateWithEncryptionKey(const string &encKey, const string &password = "mypassword") {
auto askPassword = [password] { return password;};
FakeRandomGenerator generator(Data::FromString(encKey));
auto loader = CryConfigLoader(console, generator, SCrypt::TestSettings, askPassword,
auto loader = CryConfigLoader(console, generator, localStateDir, SCrypt::TestSettings, askPassword,
askPassword, none, none, none);
ASSERT_NE(boost::none, loader.loadOrCreate(file.path(), false, false));
}
@ -151,6 +151,8 @@ public:
std::shared_ptr<MockConsole> console;
TempFile file;
cpputils::TempDir tempLocalStateDir;
LocalStateDir localStateDir;
};
TEST_F(CryConfigLoaderTest, CreatesNewIfNotExisting) {

View File

@ -33,38 +33,40 @@ using namespace cryfs;
class CryFsTest: public Test, public TestWithMockConsole, public TestWithFakeHomeDirectory {
public:
CryFsTest(): rootdir(), config(false) {
CryFsTest(): tempLocalStateDir(), localStateDir(tempLocalStateDir.path()), rootdir(), config(false) {
}
CryConfigFile loadOrCreateConfig() {
auto askPassword = [] {return "mypassword";};
return CryConfigLoader(make_shared<NoninteractiveConsole>(mockConsole()), Random::PseudoRandom(), SCrypt::TestSettings, askPassword, askPassword, none, none, none).loadOrCreate(config.path(), false, false).value().configFile;
return CryConfigLoader(make_shared<NoninteractiveConsole>(mockConsole()), Random::PseudoRandom(), localStateDir, SCrypt::TestSettings, askPassword, askPassword, none, none, none).loadOrCreate(config.path(), false, false).value().configFile;
}
unique_ref<OnDiskBlockStore2> blockStore() {
return make_unique_ref<OnDiskBlockStore2>(rootdir.path());
}
cpputils::TempDir tempLocalStateDir;
LocalStateDir localStateDir;
TempDir rootdir;
TempFile config;
};
TEST_F(CryFsTest, CreatedRootdirIsLoadableAfterClosing) {
{
CryDevice dev(loadOrCreateConfig(), blockStore(), 0x12345678, false, false);
CryDevice dev(loadOrCreateConfig(), blockStore(), localStateDir, 0x12345678, false, false);
}
CryDevice dev(loadOrCreateConfig(), blockStore(), 0x12345678, false, false);
CryDevice dev(loadOrCreateConfig(), blockStore(), localStateDir, 0x12345678, false, false);
auto rootDir = dev.LoadDir(bf::path("/"));
rootDir.value()->children();
}
TEST_F(CryFsTest, LoadingFilesystemDoesntModifyConfigFile) {
{
CryDevice dev(loadOrCreateConfig(), blockStore(), 0x12345678, false, false);
CryDevice dev(loadOrCreateConfig(), blockStore(), localStateDir, 0x12345678, false, false);
}
Data configAfterCreating = Data::LoadFromFile(config.path()).value();
{
CryDevice dev(loadOrCreateConfig(), blockStore(), 0x12345678, false, false);
CryDevice dev(loadOrCreateConfig(), blockStore(), localStateDir, 0x12345678, false, false);
}
Data configAfterLoading = Data::LoadFromFile(config.path()).value();
EXPECT_EQ(configAfterCreating, configAfterLoading);

View File

@ -23,16 +23,18 @@ class CryFsTestFixture: public FileSystemTestFixture, public TestWithMockConsole
public:
CryFsTestFixture()
// Don't create config tempfile yet
: configFile(false) {}
: tempLocalStateDir(), localStateDir(tempLocalStateDir.path()), configFile(false) {}
unique_ref<Device> createDevice() override {
auto blockStore = cpputils::make_unique_ref<InMemoryBlockStore2>();
auto askPassword = [] {return "mypassword";};
auto config = CryConfigLoader(make_shared<NoninteractiveConsole>(mockConsole()), Random::PseudoRandom(), SCrypt::TestSettings, askPassword, askPassword, none, none, none)
auto config = CryConfigLoader(make_shared<NoninteractiveConsole>(mockConsole()), Random::PseudoRandom(), localStateDir, SCrypt::TestSettings, askPassword, askPassword, none, none, none)
.loadOrCreate(configFile.path(), false, false).value();
return make_unique_ref<CryDevice>(std::move(config.configFile), std::move(blockStore), config.myClientId, false, false);
return make_unique_ref<CryDevice>(std::move(config.configFile), std::move(blockStore), localStateDir, config.myClientId, false, false);
}
cpputils::TempDir tempLocalStateDir;
LocalStateDir localStateDir;
cpputils::TempFile configFile;
};

View File

@ -9,9 +9,9 @@
class CryTestBase : public TestWithFakeHomeDirectory {
public:
CryTestBase(): _configFile(false), _device(nullptr) {
CryTestBase(): _tempLocalStateDir(), _localStateDir(_tempLocalStateDir.path()), _configFile(false), _device(nullptr) {
auto fakeBlockStore = cpputils::make_unique_ref<blockstore::inmemory::InMemoryBlockStore2>();
_device = std::make_unique<cryfs::CryDevice>(configFile(), std::move(fakeBlockStore), 0x12345678, false, false);
_device = std::make_unique<cryfs::CryDevice>(configFile(), std::move(fakeBlockStore), _localStateDir, 0x12345678, false, false);
}
cryfs::CryConfigFile configFile() {
@ -27,6 +27,8 @@ public:
}
private:
cpputils::TempDir _tempLocalStateDir;
cryfs::LocalStateDir _localStateDir;
cpputils::TempFile _configFile;
std::unique_ptr<cryfs::CryDevice> _device;
};

View File

@ -14,6 +14,9 @@ using FilesystemID = cryfs::CryConfig::FilesystemID ;
class BasedirMetadataTest : public ::testing::Test, TestWithFakeHomeDirectory {
public:
TempDir tempLocalStateDir;
cryfs::LocalStateDir localStateDir;
TempDir tempdir;
bf::path basedir1;
bf::path basedir2;
@ -21,7 +24,9 @@ public:
const FilesystemID id2;
BasedirMetadataTest()
: tempdir()
: tempLocalStateDir()
, localStateDir(tempLocalStateDir.path())
, tempdir()
, basedir1(tempdir.path() / "my/basedir")
, basedir2(tempdir.path() / "my/other/basedir")
, id1(FilesystemID::FromString("1491BB4932A389EE14BC7090AC772972"))
@ -35,32 +40,32 @@ public:
};
TEST_F(BasedirMetadataTest, givenEmptyState_whenCalled_thenSucceeds) {
EXPECT_TRUE(BasedirMetadata::load().filesystemIdForBasedirIsCorrect(basedir1, id1));
EXPECT_TRUE(BasedirMetadata::load(localStateDir).filesystemIdForBasedirIsCorrect(basedir1, id1));
}
TEST_F(BasedirMetadataTest, givenStateWithBasedir_whenCalledForDifferentBasedir_thenSucceeds) {
BasedirMetadata::load().updateFilesystemIdForBasedir(basedir2, id1).save();
EXPECT_TRUE(BasedirMetadata::load().filesystemIdForBasedirIsCorrect(basedir1, id1));
BasedirMetadata::load(localStateDir).updateFilesystemIdForBasedir(basedir2, id1).save();
EXPECT_TRUE(BasedirMetadata::load(localStateDir).filesystemIdForBasedirIsCorrect(basedir1, id1));
}
TEST_F(BasedirMetadataTest, givenStateWithBasedir_whenCalledWithSameId_thenSucceeds) {
BasedirMetadata::load().updateFilesystemIdForBasedir(basedir1, id1).save();
EXPECT_TRUE(BasedirMetadata::load().filesystemIdForBasedirIsCorrect(basedir1, id1));
BasedirMetadata::load(localStateDir).updateFilesystemIdForBasedir(basedir1, id1).save();
EXPECT_TRUE(BasedirMetadata::load(localStateDir).filesystemIdForBasedirIsCorrect(basedir1, id1));
}
TEST_F(BasedirMetadataTest, givenStateWithBasedir_whenCalledWithDifferentId_thenFails) {
BasedirMetadata::load().updateFilesystemIdForBasedir(basedir1, id2).save();
EXPECT_FALSE(BasedirMetadata::load().filesystemIdForBasedirIsCorrect(basedir1, id1));
BasedirMetadata::load(localStateDir).updateFilesystemIdForBasedir(basedir1, id2).save();
EXPECT_FALSE(BasedirMetadata::load(localStateDir).filesystemIdForBasedirIsCorrect(basedir1, id1));
}
TEST_F(BasedirMetadataTest, givenStateWithUpdatedBasedir_whenCalledWithSameId_thenSucceeds) {
BasedirMetadata::load().updateFilesystemIdForBasedir(basedir1, id2).save();
BasedirMetadata::load().updateFilesystemIdForBasedir(basedir1, id1).save();
EXPECT_TRUE(BasedirMetadata::load().filesystemIdForBasedirIsCorrect(basedir1, id1));
BasedirMetadata::load(localStateDir).updateFilesystemIdForBasedir(basedir1, id2).save();
BasedirMetadata::load(localStateDir).updateFilesystemIdForBasedir(basedir1, id1).save();
EXPECT_TRUE(BasedirMetadata::load(localStateDir).filesystemIdForBasedirIsCorrect(basedir1, id1));
}
TEST_F(BasedirMetadataTest, givenStateWithUpdatedBasedir_whenCalledWithDifferentId_thenFails) {
BasedirMetadata::load().updateFilesystemIdForBasedir(basedir1, id2).save();
BasedirMetadata::load().updateFilesystemIdForBasedir(basedir1, id1).save();
EXPECT_FALSE(BasedirMetadata::load().filesystemIdForBasedirIsCorrect(basedir1, id2));
BasedirMetadata::load(localStateDir).updateFilesystemIdForBasedir(basedir1, id2).save();
BasedirMetadata::load(localStateDir).updateFilesystemIdForBasedir(basedir1, id1).save();
EXPECT_FALSE(BasedirMetadata::load(localStateDir).filesystemIdForBasedirIsCorrect(basedir1, id2));
}