diff options
author | Saturneric <[email protected]> | 2021-09-19 15:54:06 +0000 |
---|---|---|
committer | Saturneric <[email protected]> | 2021-09-19 15:54:06 +0000 |
commit | 0f0b9510bbb8be150984bfa8af03f43e1d4135d3 (patch) | |
tree | 6436834f05ac0fe32646dbf47488d25a98ddf8fa | |
parent | Continue to write core test code. (diff) | |
download | GpgFrontend-0f0b9510bbb8be150984bfa8af03f43e1d4135d3.tar.gz GpgFrontend-0f0b9510bbb8be150984bfa8af03f43e1d4135d3.zip |
Support multi-channel Context.
Make the test configurable.
Other modifications.
Diffstat (limited to '')
-rw-r--r-- | src/gpg/GpgContext.cpp | 35 | ||||
-rw-r--r-- | src/gpg/GpgContext.h | 31 | ||||
-rw-r--r-- | src/gpg/GpgFunctionObject.h | 113 | ||||
-rw-r--r-- | src/gpg/function/GpgKeyGetter.cpp | 1 | ||||
-rw-r--r-- | src/gpg/function/GpgKeyGetter.h | 18 | ||||
-rw-r--r-- | src/gpg/function/GpgKeyImportExportor.cpp | 64 | ||||
-rw-r--r-- | src/gpg/function/GpgKeyImportExportor.h | 22 | ||||
-rw-r--r-- | test/CMakeLists.txt | 1 | ||||
-rw-r--r-- | test/GpgCoreTest.cpp | 166 | ||||
-rw-r--r-- | test/conf/core.cfg | 6 | ||||
-rw-r--r-- | test/data/pv1.key | 82 |
11 files changed, 364 insertions, 175 deletions
diff --git a/src/gpg/GpgContext.cpp b/src/gpg/GpgContext.cpp index a8c9a6de..c1911a17 100644 --- a/src/gpg/GpgContext.cpp +++ b/src/gpg/GpgContext.cpp @@ -23,9 +23,13 @@ */ #include "gpg/GpgContext.h" -#include "GpgConstants.h" +#include <gpg-error.h> +#include <gpgme.h> #include <functional> +#include <string> + +#include "GpgConstants.h" #ifdef _WIN32 #include <windows.h> @@ -39,7 +43,10 @@ namespace GpgFrontend { * Constructor * Set up gpgme-context, set paths to app-run path */ -GpgContext::GpgContext() { +GpgContext::GpgContext(bool independent_database, + std::string db_path, + int channel) + : SingletonFunctionObject<GpgContext>(channel) { static bool _first = true; if (_first) { @@ -57,25 +64,26 @@ GpgContext::GpgContext() { check_gpg_error(gpgme_new(&_p_ctx)); _ctx_ref = CtxRefHandler(_p_ctx); - LOG(INFO) << "GpgContext _ctx_ref Created"; + DLOG(INFO) << "GpgContext _ctx_ref Created"; auto engineInfo = gpgme_ctx_get_engine_info(*this); - LOG(INFO) << "GpgContext gpgme_ctx_get_engine_info Called"; + DLOG(INFO) << "GpgContext gpgme_ctx_get_engine_info Called"; // Check ENV before running bool check_pass = false, find_openpgp = false, find_gpgconf = false, find_assuan = false, find_cms = false; while (engineInfo != nullptr) { - LOG(INFO) << gpgme_get_protocol_name(engineInfo->protocol) << " " - << engineInfo->file_name << " " << engineInfo->version; + DLOG(INFO) << gpgme_get_protocol_name(engineInfo->protocol) << " " + << engineInfo->file_name << " " << engineInfo->version; if (engineInfo->protocol == GPGME_PROTOCOL_GPGCONF && strcmp(engineInfo->version, "1.0.0") != 0) find_gpgconf = true; if (engineInfo->protocol == GPGME_PROTOCOL_OpenPGP && strcmp(engineInfo->version, "1.0.0") != 0) - find_openpgp = true, info.AppPath = engineInfo->file_name; + find_openpgp = true, info.AppPath = engineInfo->file_name, + info.DatabasePath = "default"; if (engineInfo->protocol == GPGME_PROTOCOL_CMS && strcmp(engineInfo->version, "1.0.0") != 0) find_cms = true; @@ -87,11 +95,21 @@ GpgContext::GpgContext() { if (find_gpgconf && find_openpgp && find_cms && find_assuan) check_pass = true; - LOG(INFO) << "GpgContext check_pass " << check_pass; + DLOG(INFO) << "GpgContext check_pass " << check_pass; if (!check_pass) { good_ = false; return; } else { + // Set Independent Database + if (independent_database) { + info.DatabasePath = db_path; + auto err = gpgme_ctx_set_engine_info( + _ctx_ref.get(), GPGME_PROTOCOL_OpenPGP, info.AppPath.c_str(), + info.DatabasePath.c_str()); + assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR); + DLOG(INFO) << "Set independent_database path" << db_path; + } + /** Setting the output type must be done at the beginning */ /** think this means ascii-armor --> ? */ gpgme_set_armor(*this, 1); @@ -104,6 +122,7 @@ GpgContext::GpgContext() { GPGME_KEYLIST_MODE_WITH_TOFU)); good_ = true; } + DLOG(INFO) << "GpgContext init done "; } bool GpgContext::good() const { diff --git a/src/gpg/GpgContext.h b/src/gpg/GpgContext.h index 21fb5aee..0aa41f2f 100644 --- a/src/gpg/GpgContext.h +++ b/src/gpg/GpgContext.h @@ -35,21 +35,22 @@ namespace GpgFrontend { * Custom Encapsulation of GpgME APIs */ class GpgContext : public SingletonFunctionObject<GpgContext> { - -public: - GpgContext(); + public: + GpgContext(bool independent_database = false, + std::string path = std::string(), + int channel = 0); ~GpgContext() override = default; [[nodiscard]] bool good() const; - [[nodiscard]] const GpgInfo &GetInfo() const { return info; } + [[nodiscard]] const GpgInfo& GetInfo() const { return info; } static std::string getGpgmeVersion(); operator gpgme_ctx_t() const { return _ctx_ref.get(); } -private: + private: GpgInfo info; struct _ctx_ref_deletor { @@ -59,17 +60,17 @@ private: } }; - using CtxRefHandler = - std::unique_ptr<struct gpgme_context, _ctx_ref_deletor>; + using CtxRefHandler = std::unique_ptr<struct gpgme_context, _ctx_ref_deletor>; CtxRefHandler _ctx_ref = nullptr; bool good_ = true; -public: - static gpgme_error_t test_passphrase_cb(void *opaque, const char *uid_hint, - const char *passphrase_info, - int last_was_bad, int fd) { - + public: + static gpgme_error_t test_passphrase_cb(void* opaque, + const char* uid_hint, + const char* passphrase_info, + int last_was_bad, + int fd) { LOG(INFO) << "test_passphrase_cb Called"; size_t res; char pass[] = "abcdefg\n"; @@ -82,7 +83,7 @@ public: (void)last_was_bad; do { - res = gpgme_io_write(fd, &pass[off], pass_len - off); + res = gpgme_io_write(fd, &pass[off], pass_len - off); if (res > 0) off += res; } while (res > 0 && off != pass_len); @@ -92,6 +93,6 @@ public: void SetPassphraseCb(decltype(test_passphrase_cb) func) const; }; -} // namespace GpgFrontend +} // namespace GpgFrontend -#endif // __SGPGMEPP_CONTEXT_H__ +#endif // __SGPGMEPP_CONTEXT_H__ diff --git a/src/gpg/GpgFunctionObject.h b/src/gpg/GpgFunctionObject.h index 654f81d3..cb55cf92 100644 --- a/src/gpg/GpgFunctionObject.h +++ b/src/gpg/GpgFunctionObject.h @@ -25,44 +25,121 @@ #ifndef GPGFRONTEND_ZH_CN_TS_FUNCTIONOBJECT_H #define GPGFRONTEND_ZH_CN_TS_FUNCTIONOBJECT_H +#include <map> #include <memory> #include <mutex> +#include <shared_mutex> +#include <stdexcept> +#include <string> #include <easyloggingpp/easylogging++.h> namespace GpgFrontend { -template <typename T> class SingletonFunctionObject { -public: - static T &GetInstance() { - LOG(INFO) << "SingletonFunctionObject GetInstance Calling " - << typeid(T).name(); - std::lock_guard<std::mutex> guard(_instance_mutex); - if (_instance == nullptr) - _instance = std::make_unique<T>(); - return *_instance; + +template <typename T> +class SingletonFunctionObject { + public: + static T& GetInstance(int channel = 0) { + DLOG(INFO) << "SingletonFunctionObject GetInstance Calling " + << typeid(T).name() << " channel " << channel; + if (!channel) { + std::lock_guard<std::mutex> guard(_instance_mutex); + if (_instance == nullptr) + _instance = std::make_unique<T>(); + return *_instance; + } else { + // read _instances_map + decltype(_instances_map.end()) _it; + { + std::shared_lock lock(_instances_mutex); + _it = _instances_map.find(channel); + } + if (_it != _instances_map.end()) + return *_it->second; + else + return CreateInstance(channel); + } } - SingletonFunctionObject(T &&) = delete; + static T& CreateInstance(int channel, std::unique_ptr<T> p_obj = nullptr) { + DLOG(INFO) << "SingletonFunctionObject CreateInstance Calling " + << typeid(T).name() << " channel " << channel; + if (!channel) + return *_instance; + + // read _instances_map + decltype(_instances_map.end()) _it; + { + std::shared_lock lock(_instances_mutex); + _it = _instances_map.find(channel); + } + if (_it == _instances_map.end()) { + { + std::lock_guard<std::mutex> guard(_default_channel_mutex); + int tmp = channel; + std::swap(_default_channel, tmp); + if (p_obj == nullptr) + p_obj = std::make_unique<T>(); + std::swap(_default_channel, tmp); + } + T* obj = p_obj.get(); + + // change _instances_map + { + std::unique_lock lock(_instances_mutex); + _instances_map.insert({channel, std::move(p_obj)}); + } + return *obj; + } else { + return *_it->second; + } + } + + static int GetDefaultChannel() { return _default_channel; } + + int GetChannel() const { return channel_; } + + SingletonFunctionObject(T&&) = delete; + + SingletonFunctionObject(const T&) = delete; - SingletonFunctionObject(const T &) = delete; + void operator=(const T&) = delete; - void operator=(const T &) = delete; + protected: + SingletonFunctionObject() {} -protected: - SingletonFunctionObject() = default; + SingletonFunctionObject(int channel) : channel_(channel) {} virtual ~SingletonFunctionObject() = default; -private: + private: + int channel_ = _default_channel; + static int _default_channel; + static std::mutex _default_channel_mutex; static std::mutex _instance_mutex; + static std::shared_mutex _instances_mutex; static std::unique_ptr<T> _instance; + static std::map<int, std::unique_ptr<T>> _instances_map; }; -template <typename T> std::mutex SingletonFunctionObject<T>::_instance_mutex; +template <typename T> +int SingletonFunctionObject<T>::_default_channel = 0; + +template <typename T> +std::mutex SingletonFunctionObject<T>::_default_channel_mutex; + +template <typename T> +std::mutex SingletonFunctionObject<T>::_instance_mutex; + +template <typename T> +std::shared_mutex SingletonFunctionObject<T>::_instances_mutex; template <typename T> std::unique_ptr<T> SingletonFunctionObject<T>::_instance = nullptr; -} // namespace GpgFrontend +template <typename T> +std::map<int, std::unique_ptr<T>> SingletonFunctionObject<T>::_instances_map; + +} // namespace GpgFrontend -#endif // GPGFRONTEND_ZH_CN_TS_FUNCTIONOBJECT_H +#endif // GPGFRONTEND_ZH_CN_TS_FUNCTIONOBJECT_H diff --git a/src/gpg/function/GpgKeyGetter.cpp b/src/gpg/function/GpgKeyGetter.cpp index 6d80088a..ab907ea7 100644 --- a/src/gpg/function/GpgKeyGetter.cpp +++ b/src/gpg/function/GpgKeyGetter.cpp @@ -32,6 +32,7 @@ GpgFrontend::GpgKey GpgFrontend::GpgKeyGetter::GetKey(const std::string& fpr) { gpgme_get_key(ctx, fpr.c_str(), &_p_key, 1); if (_p_key == nullptr) DLOG(WARNING) << "GpgKeyGetter GetKey _p_key Null"; + assert(_p_key != nullptr); return GpgKey(std::move(_p_key)); } diff --git a/src/gpg/function/GpgKeyGetter.h b/src/gpg/function/GpgKeyGetter.h index 3a291d2d..af22e2f2 100644 --- a/src/gpg/function/GpgKeyGetter.h +++ b/src/gpg/function/GpgKeyGetter.h @@ -32,19 +32,19 @@ namespace GpgFrontend { class GpgKeyGetter : public SingletonFunctionObject<GpgKeyGetter> { + public: + GpgKeyGetter() = default; -public: - GpgKey GetKey(const std::string &fpr); + GpgKey GetKey(const std::string& fpr); - GpgKey GetPubkey(const std::string &fpr); + GpgKey GetPubkey(const std::string& fpr); KeyListPtr FetchKey(); - GpgKeyGetter() = default; - -private: - GpgContext &ctx = GpgContext::GetInstance(); + private: + GpgContext& ctx = + GpgContext::GetInstance(SingletonFunctionObject::GetDefaultChannel()); }; -} // namespace GpgFrontend +} // namespace GpgFrontend -#endif // GPGFRONTEND_ZH_CN_TS_GPGKEYGETTER_H +#endif // GPGFRONTEND_ZH_CN_TS_GPGKEYGETTER_H diff --git a/src/gpg/function/GpgKeyImportExportor.cpp b/src/gpg/function/GpgKeyImportExportor.cpp index 2ee261b4..7a7af4c7 100644 --- a/src/gpg/function/GpgKeyImportExportor.cpp +++ b/src/gpg/function/GpgKeyImportExportor.cpp @@ -1,32 +1,62 @@ +/** + * This file is part of GPGFrontend. + * + * GPGFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + #include "gpg/function/GpgKeyImportExportor.h" + #include "GpgConstants.h" -#include <gpg-error.h> /** * Import key pair * @param inBuffer input byte array * @return Import information */ -GpgFrontend::GpgImportInformation -GpgFrontend::GpgKeyImportExportor::ImportKey(StdBypeArrayPtr in_buffer) { - LOG(INFO) << "ImportKey Called in_buffer Size " << in_buffer->size(); +GpgFrontend::GpgImportInformation GpgFrontend::GpgKeyImportExportor::ImportKey( + StdBypeArrayPtr in_buffer) { + DLOG(INFO) << "ImportKey called in_buffer Size " << in_buffer->size(); + + if (in_buffer->empty()) + return GpgImportInformation(); + GpgData data_in(in_buffer->data(), in_buffer->size()); + DLOG(INFO) << "ImportKey gpgme_op_import"; auto err = check_gpg_error(gpgme_op_import(ctx, data_in)); assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR); gpgme_import_result_t result; - + DLOG(INFO) << "ImportKey gpgme_op_import_result"; result = gpgme_op_import_result(ctx); gpgme_import_status_t status = result->imports; auto import_info = std::make_unique<GpgImportInformation>(result); - LOG(INFO) << "ImportKey import_information " << result->not_imported << " " - << result->imported << " " << result->considered; + DLOG(INFO) << "ImportKey import_information " << result->not_imported << " " + << result->imported << " " << result->considered; while (status != nullptr) { GpgImportedKey key; key.import_status = static_cast<int>(status->status); key.fpr = status->fpr; import_info->importedKeys.emplace_back(key); status = status->next; - LOG(INFO) << "ImportKey Fpr " << key.fpr << " Status " << key.import_status; + DLOG(INFO) << "ImportKey Fpr " << key.fpr << " Status " + << key.import_status; } return *import_info; } @@ -38,7 +68,8 @@ GpgFrontend::GpgKeyImportExportor::ImportKey(StdBypeArrayPtr in_buffer) { * @return if success */ bool GpgFrontend::GpgKeyImportExportor::ExportKeys( - KeyIdArgsListPtr &uid_list, BypeArrayPtr &out_buffer) const { + KeyIdArgsListPtr& uid_list, + BypeArrayPtr& out_buffer) const { if (uid_list->empty()) return false; @@ -49,8 +80,8 @@ bool GpgFrontend::GpgKeyImportExportor::ExportKeys( auto err = gpgme_op_export(ctx, (*uid_list)[i].c_str(), 0, data_out); assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR); - LOG(INFO) << "exportKeys read_bytes" - << gpgme_data_seek(data_out, 0, SEEK_END); + DLOG(INFO) << "exportKeys read_bytes" + << gpgme_data_seek(data_out, 0, SEEK_END); auto temp_out_buffer = data_out.Read2Buffer(); std::swap(out_buffer, temp_out_buffer); @@ -66,9 +97,10 @@ bool GpgFrontend::GpgKeyImportExportor::ExportKeys( * @return if success */ bool GpgFrontend::GpgKeyImportExportor::ExportKeys( - KeyArgsList &keys, BypeArrayPtr &out_buffer) const { + KeyArgsList& keys, + BypeArrayPtr& out_buffer) const { KeyIdArgsListPtr key_ids = std::make_unique<std::vector<std::string>>(); - for (const auto &key : keys) + for (const auto& key : keys) key_ids->push_back(key.id()); return ExportKeys(key_ids, out_buffer); } @@ -80,9 +112,9 @@ bool GpgFrontend::GpgKeyImportExportor::ExportKeys( * @return if successful */ bool GpgFrontend::GpgKeyImportExportor::ExportSecretKey( - const GpgKey &key, BypeArrayPtr out_buffer) const { - - LOG(INFO) << "Export Secret Key" << key.id().c_str(); + const GpgKey& key, + BypeArrayPtr out_buffer) const { + DLOG(INFO) << "Export Secret Key" << key.id().c_str(); gpgme_key_t target_key[2] = {gpgme_key_t(key), nullptr}; diff --git a/src/gpg/function/GpgKeyImportExportor.h b/src/gpg/function/GpgKeyImportExportor.h index 455e59f8..2cdb4e80 100644 --- a/src/gpg/function/GpgKeyImportExportor.h +++ b/src/gpg/function/GpgKeyImportExportor.h @@ -25,6 +25,7 @@ #ifndef _GPGKEYIMPORTEXPORTOR_H #define _GPGKEYIMPORTEXPORTOR_H +#include <string> #include "gpg/GpgConstants.h" #include "gpg/GpgContext.h" #include "gpg/GpgFunctionObject.h" @@ -33,7 +34,7 @@ namespace GpgFrontend { class GpgImportedKey { -public: + public: std::string fpr; int import_status; }; @@ -41,7 +42,7 @@ public: typedef std::list<GpgImportedKey> GpgImportedKeyList; class GpgImportInformation { -public: + public: GpgImportInformation() = default; explicit GpgImportInformation(gpgme_import_result_t result) { @@ -93,19 +94,20 @@ public: class GpgKeyImportExportor : public SingletonFunctionObject<GpgKeyImportExportor> { -public: + public: GpgImportInformation ImportKey(StdBypeArrayPtr inBuffer); - bool ExportKeys(KeyIdArgsListPtr &uid_list, BypeArrayPtr &out_buffer) const; + bool ExportKeys(KeyIdArgsListPtr& uid_list, BypeArrayPtr& out_buffer) const; - bool ExportKeys(KeyArgsList &keys, BypeArrayPtr &outBuffer) const; + bool ExportKeys(KeyArgsList& keys, BypeArrayPtr& outBuffer) const; - bool ExportSecretKey(const GpgKey &key, BypeArrayPtr outBuffer) const; + bool ExportSecretKey(const GpgKey& key, BypeArrayPtr outBuffer) const; -private: - GpgContext &ctx = GpgContext::GetInstance(); + private: + GpgContext& ctx = + GpgContext::GetInstance(SingletonFunctionObject::GetDefaultChannel()); }; -} // namespace GpgFrontend +} // namespace GpgFrontend -#endif // _GPGKEYIMPORTEXPORTOR_H
\ No newline at end of file +#endif // _GPGKEYIMPORTEXPORTOR_H
\ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4e223f63..8a5859f4 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -2,6 +2,7 @@ find_package(GTest REQUIRED) # Set configure for test file(COPY ${CMAKE_SOURCE_DIR}/test/conf DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/ FOLLOW_SYMLINK_CHAIN) +file(COPY ${CMAKE_SOURCE_DIR}/test/data DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/ FOLLOW_SYMLINK_CHAIN) aux_source_directory(. TEST_SOURCE) diff --git a/test/GpgCoreTest.cpp b/test/GpgCoreTest.cpp index 51510e9e..7705e8b0 100644 --- a/test/GpgCoreTest.cpp +++ b/test/GpgCoreTest.cpp @@ -28,7 +28,12 @@ #include <gtest/gtest.h> #include <boost/date_time/gregorian/parsers.hpp> #include <boost/dll.hpp> +#include <boost/filesystem/operations.hpp> +#include <boost/filesystem/path.hpp> +#include <fstream> #include <memory> +#include <string> +#include <vector> #include "gpg/GpgConstants.h" #include "gpg/function/GpgKeyGetter.h" @@ -38,97 +43,19 @@ TEST(GpgKeyTest, GpgCoreTest) {} class GpgCoreTest : public ::testing::Test { protected: - GpgFrontend::StdBypeArrayPtr secret_key_ = std::make_unique<std::string>( - "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" - "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" - "T2R+xoMRGcJJphKWpVjZ" - "=u+uG" - "\n-----END PGP PRIVATE KEY BLOCK-----\n"); + std::vector<GpgFrontend::StdBypeArrayPtr> secret_keys_; + + boost::filesystem::path parent_path = + boost::dll::program_location().parent_path(); + + boost::filesystem::path config_path = parent_path / "conf" / "core.cfg"; GpgCoreTest() = default; virtual ~GpgCoreTest() = default; virtual void SetUp() { - auto config_path = - boost::dll::program_location().parent_path() / "conf" / "core.cfg"; - + DLOG(INFO) << "SetUp called"; using namespace libconfig; Config cfg; ASSERT_NO_THROW(cfg.readFile(config_path.c_str())); @@ -137,12 +64,53 @@ class GpgCoreTest : public ::testing::Test { ASSERT_TRUE(root.exists("independent_database")); bool independent_database = true; ASSERT_TRUE(root.lookupValue("independent_database", independent_database)); - if (independent_database) - GpgFrontend::GpgContext::GetInstance().SetPassphraseCb( - GpgFrontend::GpgContext::test_passphrase_cb); - GpgFrontend::GpgKeyImportExportor::GetInstance().ImportKey( - std::move(this->secret_key_)); + DLOG(INFO) << "SetUp independent_database"; + if (independent_database) { + ASSERT_TRUE(root.exists("independent_db_path")); + std::string relative_db_path; + + ASSERT_TRUE(root.lookupValue("independent_db_path", relative_db_path)); + + auto db_path = parent_path / relative_db_path; + if (!boost::filesystem::exists(db_path)) { + boost::filesystem::create_directory(db_path); + } + + DLOG(INFO) << "GpgFrontend::GpgContext::CreateInstance"; + GpgFrontend::GpgContext::CreateInstance( + 1, std::make_unique<GpgFrontend::GpgContext>(true, db_path.c_str())); + DLOG(INFO) << "db_path " << db_path; + } + + ASSERT_TRUE(root.exists("data_path")); + std::string relative_data_path; + ASSERT_TRUE(root.lookupValue("data_path", relative_data_path)); + auto data_path = parent_path / relative_data_path; + ASSERT_TRUE(boost::filesystem::exists(data_path)); + + if (root.exists("load_keys.private_keys")) { + LOG(INFO) << "loading private keys"; + auto& private_keys = root.lookup("load_keys.private_keys"); + for (auto it = private_keys.begin(); it != private_keys.end(); it++) { + ASSERT_TRUE(it->exists("filename")); + std::string filename; + it->lookupValue("filename", filename); + auto data_file_path = data_path / filename; + DLOG(INFO) << "private file path" << data_file_path.string(); + std::string data = + GpgFrontend::read_all_data_in_file(data_file_path.string()); + secret_keys_.push_back(std::make_unique<std::string>(data)); + } + LOG(INFO) << "loaded private keys"; + } + + GpgFrontend::GpgContext::GetInstance(1).SetPassphraseCb( + GpgFrontend::GpgContext::test_passphrase_cb); + for (auto& secret_key : secret_keys_) { + GpgFrontend::GpgKeyImportExportor::GetInstance(1).ImportKey( + std::move(secret_key)); + } } virtual void TearDown() {} @@ -154,7 +122,11 @@ class GpgCoreTest : public ::testing::Test { }; TEST_F(GpgCoreTest, CoreInitTest) { - auto& ctx = GpgFrontend::GpgContext::GetInstance(); + auto& ctx = GpgFrontend::GpgContext::GetInstance(1); + DLOG(INFO) << "CoreInitTest ctx DatabasePath " << ctx.GetInfo().DatabasePath; + auto& ctx_default = GpgFrontend::GpgContext::GetInstance(); + DLOG(INFO) << "CoreInitTest ctx_default DatabasePath " + << ctx_default.GetInfo().DatabasePath; ASSERT_TRUE(ctx.good()); } @@ -171,7 +143,7 @@ TEST_F(GpgCoreTest, GpgDataTest) { } TEST_F(GpgCoreTest, GpgKeyTest) { - auto key = GpgFrontend::GpgKeyGetter::GetInstance().GetKey( + auto key = GpgFrontend::GpgKeyGetter::GetInstance(1).GetKey( "9490795B78F8AFE9F93BD09281704859182661FB"); ASSERT_TRUE(key.good()); ASSERT_TRUE(key.is_private_key()); @@ -214,7 +186,7 @@ TEST_F(GpgCoreTest, GpgKeyTest) { } TEST_F(GpgCoreTest, GpgSubKeyTest) { - auto key = GpgFrontend::GpgKeyGetter::GetInstance().GetKey( + auto key = GpgFrontend::GpgKeyGetter::GetInstance(1).GetKey( "9490795B78F8AFE9F93BD09281704859182661FB"); auto sub_keys = key.subKeys(); ASSERT_EQ(sub_keys->size(), 2); @@ -244,7 +216,7 @@ TEST_F(GpgCoreTest, GpgSubKeyTest) { } TEST_F(GpgCoreTest, GpgUIDTest) { - auto key = GpgFrontend::GpgKeyGetter::GetInstance().GetKey( + auto key = GpgFrontend::GpgKeyGetter::GetInstance(1).GetKey( "9490795B78F8AFE9F93BD09281704859182661FB"); auto uids = key.uids(); ASSERT_EQ(uids->size(), 1); @@ -259,7 +231,7 @@ TEST_F(GpgCoreTest, GpgUIDTest) { } TEST_F(GpgCoreTest, GpgKeySignatureTest) { - auto key = GpgFrontend::GpgKeyGetter::GetInstance().GetKey( + auto key = GpgFrontend::GpgKeyGetter::GetInstance(1).GetKey( "9490795B78F8AFE9F93BD09281704859182661FB"); auto uids = key.uids(); ASSERT_EQ(uids->size(), 1); @@ -283,10 +255,10 @@ TEST_F(GpgCoreTest, GpgKeySignatureTest) { } TEST_F(GpgCoreTest, GpgKeyGetterTest) { - auto key = GpgFrontend::GpgKeyGetter::GetInstance().GetKey( + auto key = GpgFrontend::GpgKeyGetter::GetInstance(1).GetKey( "9490795B78F8AFE9F93BD09281704859182661FB"); ASSERT_TRUE(key.good()); - auto keys = GpgFrontend::GpgKeyGetter::GetInstance().FetchKey(); + auto keys = GpgFrontend::GpgKeyGetter::GetInstance(1).FetchKey(); ASSERT_GE(keys->size(), 1); ASSERT_TRUE(find(keys->begin(), keys->end(), key) != keys->end()); diff --git a/test/conf/core.cfg b/test/conf/core.cfg index b9b194cf..4129d39f 100644 --- a/test/conf/core.cfg +++ b/test/conf/core.cfg @@ -1,7 +1,9 @@ -# Example application configuration file +# core test configuration file version = "1.0"; independent_database = true; -load_keys: +independent_db_path = "db" +data_path = "data" +load_keys = { private_keys = ({ filename = "pv1.key"; diff --git a/test/data/pv1.key b/test/data/pv1.key new file mode 100644 index 00000000..345fdf4f --- /dev/null +++ b/test/data/pv1.key @@ -0,0 +1,82 @@ +-----BEGIN PGP PRIVATE KEY BLOCK----- + +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 +T2R+xoMRGcJJphKWpVjZ +=u+uG +-----END PGP PRIVATE KEY BLOCK-----
\ No newline at end of file |