diff options
author | Saturneric <[email protected]> | 2021-09-20 09:35:57 +0000 |
---|---|---|
committer | Saturneric <[email protected]> | 2021-09-20 09:35:57 +0000 |
commit | 8544bb3ed9ccf09f3082c3032381a1b61dc5e122 (patch) | |
tree | e5b12fd9c1331718dd60926ed7b4056361a8b68f | |
parent | Support multi-channel Context. (diff) | |
download | GpgFrontend-8544bb3ed9ccf09f3082c3032381a1b61dc5e122.tar.gz GpgFrontend-8544bb3ed9ccf09f3082c3032381a1b61dc5e122.zip |
The basic functions of the core pass the test.
Adjust and improve the core part of the interface.
Diffstat (limited to '')
-rw-r--r-- | src/gpg/GpgConstants.h | 13 | ||||
-rw-r--r-- | src/gpg/GpgContext.cpp | 10 | ||||
-rw-r--r-- | src/gpg/GpgFunctionObject.h | 4 | ||||
-rw-r--r-- | src/gpg/GpgModel.h | 12 | ||||
-rw-r--r-- | src/gpg/function/BasicOperator.cpp | 58 | ||||
-rw-r--r-- | src/gpg/function/BasicOperator.h | 54 | ||||
-rw-r--r-- | src/gpg/function/GpgFileOpera.cpp | 17 | ||||
-rw-r--r-- | src/gpg/function/GpgFileOpera.h | 31 | ||||
-rw-r--r-- | src/gpg/function/GpgKeyGetter.cpp | 14 | ||||
-rw-r--r-- | src/gpg/function/GpgKeyImportExportor.cpp | 8 | ||||
-rw-r--r-- | src/gpg/model/GpgKey.h | 4 | ||||
-rw-r--r-- | test/GpgCoreTestBasicOpera.cpp | 174 | ||||
-rw-r--r-- | test/GpgCoreTestImportExport.cpp | 35 | ||||
-rw-r--r-- | test/GpgCoreTestKeyModel.cpp (renamed from test/GpgCoreTest.cpp) | 137 | ||||
-rw-r--r-- | test/GpgFrontendTest.h | 101 | ||||
-rw-r--r-- | test/conf/core.cfg | 20 | ||||
-rw-r--r-- | test/data/pv2.key | 41 | ||||
-rw-r--r-- | test/data/pv3.key | 106 | ||||
-rw-r--r-- | test/data/pv4.key | 82 |
19 files changed, 680 insertions, 241 deletions
diff --git a/src/gpg/GpgConstants.h b/src/gpg/GpgConstants.h index f891151f..0c126bf7 100644 --- a/src/gpg/GpgConstants.h +++ b/src/gpg/GpgConstants.h @@ -42,19 +42,20 @@ const int RESTART_CODE = 1000; namespace GpgFrontend { -using BypeArrayPtr = std::unique_ptr<std::string>; -using StdBypeArrayPtr = std::unique_ptr<std::string>; -using BypeArrayRef = std::string&; +using ByteArray = std::string; +using BypeArrayPtr = std::unique_ptr<ByteArray>; +using StdBypeArrayPtr = std::unique_ptr<ByteArray>; +using BypeArrayRef = ByteArray&; using StringArgsPtr = std::unique_ptr<std::vector<std::string>>; using StringArgsRef = std::vector<std::string>&; using GpgError = gpgme_error_t; -// Result +// Result Deletor struct _result_ref_deletor { void operator()(void* _result) { - if (_result != nullptr) - gpgme_result_unref(_result); + // if (_result != nullptr) + // gpgme_result_unref(_result); } }; diff --git a/src/gpg/GpgContext.cpp b/src/gpg/GpgContext.cpp index c1911a17..1372fd73 100644 --- a/src/gpg/GpgContext.cpp +++ b/src/gpg/GpgContext.cpp @@ -64,19 +64,12 @@ GpgContext::GpgContext(bool independent_database, check_gpg_error(gpgme_new(&_p_ctx)); _ctx_ref = CtxRefHandler(_p_ctx); - DLOG(INFO) << "GpgContext _ctx_ref Created"; - auto engineInfo = gpgme_ctx_get_engine_info(*this); - 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) { - 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; @@ -95,7 +88,6 @@ GpgContext::GpgContext(bool independent_database, if (find_gpgconf && find_openpgp && find_cms && find_assuan) check_pass = true; - DLOG(INFO) << "GpgContext check_pass " << check_pass; if (!check_pass) { good_ = false; return; @@ -107,7 +99,6 @@ GpgContext::GpgContext(bool independent_database, _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 */ @@ -122,7 +113,6 @@ GpgContext::GpgContext(bool independent_database, GPGME_KEYLIST_MODE_WITH_TOFU)); good_ = true; } - DLOG(INFO) << "GpgContext init done "; } bool GpgContext::good() const { diff --git a/src/gpg/GpgFunctionObject.h b/src/gpg/GpgFunctionObject.h index cb55cf92..a8746edf 100644 --- a/src/gpg/GpgFunctionObject.h +++ b/src/gpg/GpgFunctionObject.h @@ -40,8 +40,6 @@ 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) @@ -62,8 +60,6 @@ class SingletonFunctionObject { } 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; diff --git a/src/gpg/GpgModel.h b/src/gpg/GpgModel.h index f9851f1e..fcdadb5c 100644 --- a/src/gpg/GpgModel.h +++ b/src/gpg/GpgModel.h @@ -36,15 +36,15 @@ using KeyIdArgsListPtr = std::unique_ptr<std::vector<std::string>>; using KeyFprArgsListPtr = std::unique_ptr<std::vector<std::string>>; -using KeyArgsList = std::vector<GpgKey>; +using KeyArgsList = const std::vector<GpgKey>; -using KeyListPtr = std::unique_ptr<std::vector<GpgKey>>; +using KeyListPtr = std::unique_ptr<KeyArgsList>; -using GpgKeyLinkList = std::list<GpgFrontend::GpgKey>; +using GpgKeyLinkList = const std::list<GpgFrontend::GpgKey>; using KeyPtr = std::unique_ptr<GpgKey>; -using KeyPtrArgsList = std::initializer_list<KeyPtr>; -} // namespace GpgFrontend +using KeyPtrArgsList = const std::initializer_list<KeyPtr>; +} // namespace GpgFrontend -#endif // GPGFRONTEND_ZH_CN_TS_GPGMODEL_H +#endif // GPGFRONTEND_ZH_CN_TS_GPGMODEL_H diff --git a/src/gpg/function/BasicOperator.cpp b/src/gpg/function/BasicOperator.cpp index 50a2e2e3..fbf9afb1 100644 --- a/src/gpg/function/BasicOperator.cpp +++ b/src/gpg/function/BasicOperator.cpp @@ -23,17 +23,19 @@ */ #include "gpg/function/BasicOperator.h" +#include <vector> #include "gpg/function/GpgKeyGetter.h" GpgFrontend::GpgError GpgFrontend::BasicOperator::Encrypt( - std::vector<GpgKey> &keys, GpgFrontend::BypeArrayRef in_buffer, - GpgFrontend::BypeArrayPtr &out_buffer, GpgFrontend::GpgEncrResult &result) { - + GpgFrontend::KeyArgsList&& keys, + GpgFrontend::BypeArrayRef in_buffer, + GpgFrontend::BypeArrayPtr& out_buffer, + GpgFrontend::GpgEncrResult& result) { // gpgme_encrypt_result_t e_result; gpgme_key_t recipients[keys.size() + 1]; int index = 0; - for (const auto &key : keys) + for (const auto& key : keys) recipients[index++] = gpgme_key_t(key); // Last entry data_in array has to be nullptr @@ -53,11 +55,10 @@ GpgFrontend::GpgError GpgFrontend::BasicOperator::Encrypt( return err; } -GpgFrontend::GpgError -GpgFrontend::BasicOperator::Decrypt(BypeArrayRef in_buffer, - GpgFrontend::BypeArrayPtr &out_buffer, - GpgFrontend::GpgDecrResult &result) { - +GpgFrontend::GpgError GpgFrontend::BasicOperator::Decrypt( + BypeArrayRef in_buffer, + GpgFrontend::BypeArrayPtr& out_buffer, + GpgFrontend::GpgDecrResult& result) { gpgme_error_t err; GpgData data_in(in_buffer.data(), in_buffer.size()), data_out; @@ -72,10 +73,10 @@ GpgFrontend::BasicOperator::Decrypt(BypeArrayRef in_buffer, return err; } -GpgFrontend::GpgError -GpgFrontend::BasicOperator::Verify(BypeArrayRef &in_buffer, - BypeArrayPtr &sig_buffer, - GpgVerifyResult &result) const { +GpgFrontend::GpgError GpgFrontend::BasicOperator::Verify( + BypeArrayRef& in_buffer, + BypeArrayPtr& sig_buffer, + GpgVerifyResult& result) const { gpgme_error_t err; GpgData data_in(in_buffer.data(), in_buffer.size()); @@ -92,11 +93,11 @@ GpgFrontend::BasicOperator::Verify(BypeArrayRef &in_buffer, return err; } -GpgFrontend::GpgError GpgFrontend::BasicOperator::Sign(KeyArgsList &keys, +GpgFrontend::GpgError GpgFrontend::BasicOperator::Sign(KeyArgsList&& keys, BypeArrayRef in_buffer, - BypeArrayPtr &out_buffer, + BypeArrayPtr& out_buffer, gpgme_sig_mode_t mode, - GpgSignResult &result) { + GpgSignResult& result) { gpgme_error_t err; // Set Singers of this opera @@ -130,8 +131,10 @@ GpgFrontend::GpgError GpgFrontend::BasicOperator::Sign(KeyArgsList &keys, } gpgme_error_t GpgFrontend::BasicOperator::DecryptVerify( - BypeArrayRef in_buffer, BypeArrayPtr &out_buffer, - GpgDecrResult &decrypt_result, GpgVerifyResult &verify_result) { + BypeArrayRef in_buffer, + BypeArrayPtr& out_buffer, + GpgDecrResult& decrypt_result, + GpgVerifyResult& verify_result) { gpgme_error_t err; GpgData data_in(in_buffer.data(), in_buffer.size()), data_out; @@ -151,9 +154,12 @@ gpgme_error_t GpgFrontend::BasicOperator::DecryptVerify( } gpgme_error_t GpgFrontend::BasicOperator::EncryptSign( - std::vector<GpgKey> &keys, std::vector<GpgKey> &signers, - BypeArrayRef in_buffer, BypeArrayPtr &out_buffer, - GpgEncrResult &encr_result, GpgSignResult &sign_result) { + KeyArgsList&& keys, + KeyArgsList&& signers, + BypeArrayRef in_buffer, + BypeArrayPtr& out_buffer, + GpgEncrResult& encr_result, + GpgSignResult& sign_result) { gpgme_error_t err; SetSigners(signers); @@ -162,7 +168,7 @@ gpgme_error_t GpgFrontend::BasicOperator::EncryptSign( // set key for user int index = 0; - for (const auto &key : keys) + for (const auto& key : keys) recipients[index++] = gpgme_key_t(key); // Last entry dataIn array has to be nullptr @@ -185,19 +191,19 @@ gpgme_error_t GpgFrontend::BasicOperator::EncryptSign( return err; } -void GpgFrontend::BasicOperator::SetSigners(KeyArgsList &keys) { +void GpgFrontend::BasicOperator::SetSigners(KeyArgsList& keys) { gpgme_signers_clear(ctx); - for (const GpgKey &key : keys) { + for (const GpgKey& key : keys) { if (key.CanSignActual()) { auto gpgmeError = gpgme_signers_add(ctx, gpgme_key_t(key)); check_gpg_error(gpgmeError); } } if (keys.size() != gpgme_signers_count(ctx)) - LOG(INFO) << "No All Signers Added"; + DLOG(INFO) << "No All Signers Added"; } -std::unique_ptr<std::vector<GpgFrontend::GpgKey>> +std::unique_ptr<GpgFrontend::KeyArgsList> GpgFrontend::BasicOperator::GetSigners() { auto count = gpgme_signers_count(ctx); auto signers = std::make_unique<std::vector<GpgKey>>(); diff --git a/src/gpg/function/BasicOperator.h b/src/gpg/function/BasicOperator.h index e5424ad2..2e5da307 100644 --- a/src/gpg/function/BasicOperator.h +++ b/src/gpg/function/BasicOperator.h @@ -33,36 +33,46 @@ namespace GpgFrontend { class BasicOperator : public SingletonFunctionObject<BasicOperator> { -public: - gpg_error_t Encrypt(KeyArgsList &keys, BypeArrayRef in_buffer, - BypeArrayPtr &out_buffer, GpgEncrResult &result); + public: + gpg_error_t Encrypt(KeyArgsList&& keys, + BypeArrayRef in_buffer, + BypeArrayPtr& out_buffer, + GpgEncrResult& result); - gpgme_error_t EncryptSign(KeyArgsList &keys, KeyArgsList &signers, - BypeArrayRef in_buffer, BypeArrayPtr &out_buffer, - GpgEncrResult &encr_result, - GpgSignResult &sign_result); + gpgme_error_t EncryptSign(KeyArgsList&& keys, + KeyArgsList&& signers, + BypeArrayRef in_buffer, + BypeArrayPtr& out_buffer, + GpgEncrResult& encr_result, + GpgSignResult& sign_result); - gpgme_error_t Decrypt(BypeArrayRef in_buffer, BypeArrayPtr &out_buffer, - GpgDecrResult &result); + gpgme_error_t Decrypt(BypeArrayRef in_buffer, + BypeArrayPtr& out_buffer, + GpgDecrResult& result); - gpgme_error_t DecryptVerify(BypeArrayRef in_buffer, BypeArrayPtr &out_buffer, - GpgDecrResult &decrypt_result, - GpgVerifyResult &verify_result); + gpgme_error_t DecryptVerify(BypeArrayRef in_buffer, + BypeArrayPtr& out_buffer, + GpgDecrResult& decrypt_result, + GpgVerifyResult& verify_result); - gpgme_error_t Verify(BypeArrayRef in_buffer, BypeArrayPtr &sig_buffer, - GpgVerifyResult &result) const; + gpgme_error_t Verify(BypeArrayRef in_buffer, + BypeArrayPtr& sig_buffer, + GpgVerifyResult& result) const; - gpg_error_t Sign(KeyArgsList &key_fprs, BypeArrayRef in_buffer, - BypeArrayPtr &out_buffer, gpgme_sig_mode_t mode, - GpgSignResult &result); + gpg_error_t Sign(KeyArgsList&& key_fprs, + BypeArrayRef in_buffer, + BypeArrayPtr& out_buffer, + gpgme_sig_mode_t mode, + GpgSignResult& result); - void SetSigners(KeyArgsList &keys); + void SetSigners(KeyArgsList& keys); std::unique_ptr<KeyArgsList> GetSigners(); -private: - GpgContext &ctx = GpgContext::GetInstance(); + private: + GpgContext& ctx = + GpgContext::GetInstance(SingletonFunctionObject::GetDefaultChannel()); }; -} // namespace GpgFrontend +} // namespace GpgFrontend -#endif // GPGFRONTEND_ZH_CN_TS_BASICOPERATOR_H +#endif // GPGFRONTEND_ZH_CN_TS_BASICOPERATOR_H diff --git a/src/gpg/function/GpgFileOpera.cpp b/src/gpg/function/GpgFileOpera.cpp index 79214d2d..0f78c30c 100644 --- a/src/gpg/function/GpgFileOpera.cpp +++ b/src/gpg/function/GpgFileOpera.cpp @@ -32,14 +32,14 @@ #include <string> GpgFrontend::GpgError GpgFrontend::GpgFileOpera::EncryptFile( - KeyArgsList& keys, + KeyArgsList&& keys, const std::string& path, GpgEncrResult& result) { std::string in_buffer = read_all_data_in_file(path); std::unique_ptr<std::string> out_buffer; - auto err = - BasicOperator::GetInstance().Encrypt(keys, in_buffer, out_buffer, result); + auto err = BasicOperator::GetInstance().Encrypt(std::move(keys), in_buffer, + out_buffer, result); assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR); @@ -69,14 +69,14 @@ GpgFrontend::GpgError GpgFrontend::GpgFileOpera::DecryptFile( return err; } -gpgme_error_t GpgFrontend::GpgFileOpera::SignFile(KeyArgsList& keys, +gpgme_error_t GpgFrontend::GpgFileOpera::SignFile(KeyArgsList&& keys, const std::string& path, GpgSignResult& result) { auto in_buffer = read_all_data_in_file(path); std::unique_ptr<std::string> out_buffer; - auto err = BasicOperator::GetInstance().Sign(keys, in_buffer, out_buffer, - GPGME_SIG_MODE_DETACH, result); + auto err = BasicOperator::GetInstance().Sign( + std::move(keys), in_buffer, out_buffer, GPGME_SIG_MODE_DETACH, result); assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR); @@ -108,7 +108,7 @@ gpgme_error_t GpgFrontend::GpgFileOpera::VerifyFile(const std::string& path, // TODO gpg_error_t GpgFrontend::GpgFileOpera::EncryptSignFile( - KeyArgsList& keys, + KeyArgsList&& keys, const std::string& path, GpgEncrResult& encr_res, GpgSignResult& sign_res) { @@ -120,7 +120,8 @@ gpg_error_t GpgFrontend::GpgFileOpera::EncryptSignFile( // TODO dealing with signer keys auto err = BasicOperator::GetInstance().EncryptSign( - keys, signerKeys, in_buffer, out_buffer, encr_res, sign_res); + std::move(keys), std::move(signerKeys), in_buffer, out_buffer, encr_res, + sign_res); assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR); diff --git a/src/gpg/function/GpgFileOpera.h b/src/gpg/function/GpgFileOpera.h index 582dbbd2..2eac251b 100644 --- a/src/gpg/function/GpgFileOpera.h +++ b/src/gpg/function/GpgFileOpera.h @@ -32,24 +32,29 @@ namespace GpgFrontend { class GpgFileOpera { -public: - GpgError EncryptFile(KeyArgsList &keys, const std::string &path, - GpgEncrResult &result); + public: + GpgError EncryptFile(KeyArgsList&& keys, + const std::string& path, + GpgEncrResult& result); - GpgError DecryptFile(const std::string &path, GpgDecrResult &result); + GpgError DecryptFile(const std::string& path, GpgDecrResult& result); - GpgError SignFile(KeyArgsList &keys, const std::string &path, - GpgSignResult &result); + GpgError SignFile(KeyArgsList&& keys, + const std::string& path, + GpgSignResult& result); - GpgError VerifyFile(const std::string &path, GpgVerifyResult &result); + GpgError VerifyFile(const std::string& path, GpgVerifyResult& result); - GpgError EncryptSignFile(KeyArgsList &keys, const std::string &path, - GpgEncrResult &encr_res, GpgSignResult &sign_res); + GpgError EncryptSignFile(KeyArgsList&& keys, + const std::string& path, + GpgEncrResult& encr_res, + GpgSignResult& sign_res); - GpgError DecryptVerifyFile(const std::string &path, GpgDecrResult &decr_res, - GpgVerifyResult &verify_res); + GpgError DecryptVerifyFile(const std::string& path, + GpgDecrResult& decr_res, + GpgVerifyResult& verify_res); }; -} // namespace GpgFrontend +} // namespace GpgFrontend -#endif // GPGFRONTEND_GPGFILEOPERA_H +#endif // GPGFRONTEND_GPGFILEOPERA_H diff --git a/src/gpg/function/GpgKeyGetter.cpp b/src/gpg/function/GpgKeyGetter.cpp index ab907ea7..f2413706 100644 --- a/src/gpg/function/GpgKeyGetter.cpp +++ b/src/gpg/function/GpgKeyGetter.cpp @@ -27,7 +27,6 @@ #include "GpgConstants.h" GpgFrontend::GpgKey GpgFrontend::GpgKeyGetter::GetKey(const std::string& fpr) { - DLOG(INFO) << "GpgKeyGetter GetKey Fpr " << fpr; gpgme_key_t _p_key; gpgme_get_key(ctx, fpr.c_str(), &_p_key, 1); if (_p_key == nullptr) @@ -40,34 +39,27 @@ GpgFrontend::GpgKey GpgFrontend::GpgKeyGetter::GetPubkey( const std::string& fpr) { gpgme_key_t _p_key; gpgme_get_key(ctx, fpr.c_str(), &_p_key, 0); + if (_p_key == nullptr) + DLOG(WARNING) << "GpgKeyGetter GetKey _p_key Null"; return GpgKey(std::move(_p_key)); } GpgFrontend::KeyListPtr GpgFrontend::GpgKeyGetter::FetchKey() { gpgme_error_t err; - DLOG(INFO) << "Clear List and Map"; - - KeyListPtr keys_list = std::make_unique<std::vector<GpgKey>>(); - - DLOG(INFO) << "Operate KeyList Start"; + auto keys_list = std::make_unique<std::vector<GpgKey>>(); err = gpgme_op_keylist_start(ctx, nullptr, 0); assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR); - DLOG(INFO) << "Start Loop"; - gpgme_key_t key; while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR) { keys_list->push_back(GpgKey(std::move(key))); - DLOG(INFO) << "Append Key" << keys_list->back().id().c_str(); } assert(check_gpg_error_2_err_code(err, GPG_ERR_EOF) == GPG_ERR_EOF); err = gpgme_op_keylist_end(ctx); - DLOG(INFO) << "Operate KeyList End"; - return keys_list; } diff --git a/src/gpg/function/GpgKeyImportExportor.cpp b/src/gpg/function/GpgKeyImportExportor.cpp index 7a7af4c7..98ffc328 100644 --- a/src/gpg/function/GpgKeyImportExportor.cpp +++ b/src/gpg/function/GpgKeyImportExportor.cpp @@ -33,30 +33,22 @@ */ 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); - 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; - DLOG(INFO) << "ImportKey Fpr " << key.fpr << " Status " - << key.import_status; } return *import_info; } diff --git a/src/gpg/model/GpgKey.h b/src/gpg/model/GpgKey.h index 52e089ff..1aa307e6 100644 --- a/src/gpg/model/GpgKey.h +++ b/src/gpg/model/GpgKey.h @@ -137,9 +137,9 @@ class GpgKey { GpgKey& operator=(const gpgme_key_t& key) = delete; - bool operator==(const GpgKey& o) { return o.id() == this->id(); } + bool operator==(const GpgKey& o) const { return o.id() == this->id(); } - bool operator<=(const GpgKey& o) { return this->id() < o.id(); } + bool operator<=(const GpgKey& o) const { return this->id() < o.id(); } explicit operator gpgme_key_t() const { return _key_ref.get(); } diff --git a/test/GpgCoreTestBasicOpera.cpp b/test/GpgCoreTestBasicOpera.cpp new file mode 100644 index 00000000..12cc3def --- /dev/null +++ b/test/GpgCoreTestBasicOpera.cpp @@ -0,0 +1,174 @@ +/** + * 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 <gtest/gtest.h> +#include "GpgFrontendTest.h" + +#include <string> +#include <vector> + +#include "gpg/GpgConstants.h" +#include "gpg/function/BasicOperator.h" +#include "gpg/function/GpgKeyGetter.h" +#include "gpg/model/GpgKey.h" + +using namespace GpgFrontend; + +TEST_F(GpgCoreTest, CoreEncryptDecrTest) { + auto encrpyt_key = GpgKeyGetter::GetInstance(default_channel) + .GetPubkey("467F14220CE8DCF780CF4BAD8465C55B25C9B7D1"); + ByteArray encrypt_text = "Hello GpgFrontend!"; + BypeArrayPtr encr_out_data; + GpgEncrResult e_result; + std::vector<GpgKey> keys; + keys.push_back(std::move(encrpyt_key)); + auto err = + BasicOperator::GetInstance(default_channel) + .Encrypt(std::move(keys), encrypt_text, encr_out_data, e_result); + ASSERT_EQ(e_result->invalid_recipients, nullptr); + ASSERT_EQ(check_gpg_error_2_err_code(err), GPG_ERR_NO_ERROR); + + GpgDecrResult d_result; + BypeArrayPtr decr_out_data; + err = BasicOperator::GetInstance(default_channel) + .Decrypt(*encr_out_data, decr_out_data, d_result); + ASSERT_EQ(check_gpg_error_2_err_code(err), GPG_ERR_NO_ERROR); + ASSERT_NE(d_result->recipients, nullptr); + ASSERT_EQ(std::string(d_result->recipients->keyid), "F89C95A05088CC93"); + ASSERT_EQ(*decr_out_data, encrypt_text); +} + +TEST_F(GpgCoreTest, CoreSignVerifyNormalTest) { + auto encrpyt_key = GpgKeyGetter::GetInstance(default_channel) + .GetPubkey("467F14220CE8DCF780CF4BAD8465C55B25C9B7D1"); + ByteArray sign_text = "Hello GpgFrontend!"; + BypeArrayPtr sign_out_data; + GpgSignResult s_result; + std::vector<GpgKey> keys; + keys.push_back(std::move(encrpyt_key)); + auto err = BasicOperator::GetInstance(default_channel) + .Sign(std::move(keys), sign_text, sign_out_data, + GPGME_SIG_MODE_NORMAL, s_result); + ASSERT_EQ(check_gpg_error_2_err_code(err), GPG_ERR_NO_ERROR); + ASSERT_EQ(s_result->invalid_signers, nullptr); + + GpgVerifyResult v_result; + BypeArrayPtr sign_buff = nullptr; + err = BasicOperator::GetInstance(default_channel) + .Verify(*sign_out_data, sign_buff, v_result); + ASSERT_EQ(check_gpg_error_2_err_code(err), GPG_ERR_NO_ERROR); + ASSERT_NE(v_result->signatures, nullptr); + ASSERT_EQ(std::string(v_result->signatures->fpr), + "467F14220CE8DCF780CF4BAD8465C55B25C9B7D1"); + ASSERT_EQ(v_result->signatures->next, nullptr); +} + +TEST_F(GpgCoreTest, CoreSignVerifyDetachTest) { + auto encrpyt_key = GpgKeyGetter::GetInstance(default_channel) + .GetPubkey("467F14220CE8DCF780CF4BAD8465C55B25C9B7D1"); + ByteArray sign_text = "Hello GpgFrontend!"; + BypeArrayPtr sign_out_data; + GpgSignResult s_result; + std::vector<GpgKey> keys; + keys.push_back(std::move(encrpyt_key)); + auto err = BasicOperator::GetInstance(default_channel) + .Sign(std::move(keys), sign_text, sign_out_data, + GPGME_SIG_MODE_DETACH, s_result); + ASSERT_EQ(check_gpg_error_2_err_code(err), GPG_ERR_NO_ERROR); + ASSERT_EQ(s_result->invalid_signers, nullptr); + + GpgVerifyResult v_result; + err = BasicOperator::GetInstance(default_channel) + .Verify(sign_text, sign_out_data, v_result); + ASSERT_EQ(check_gpg_error_2_err_code(err), GPG_ERR_NO_ERROR); + ASSERT_NE(v_result->signatures, nullptr); + ASSERT_EQ(std::string(v_result->signatures->fpr), + "467F14220CE8DCF780CF4BAD8465C55B25C9B7D1"); + ASSERT_EQ(v_result->signatures->next, nullptr); +} + +TEST_F(GpgCoreTest, CoreSignVerifyClearTest) { + auto sign_key = GpgKeyGetter::GetInstance(default_channel) + .GetKey("467F14220CE8DCF780CF4BAD8465C55B25C9B7D1"); + ByteArray sign_text = "Hello GpgFrontend!"; + BypeArrayPtr sign_out_data; + GpgSignResult s_result; + std::vector<GpgKey> keys; + keys.push_back(std::move(sign_key)); + auto err = BasicOperator::GetInstance(default_channel) + .Sign(std::move(keys), sign_text, sign_out_data, + GPGME_SIG_MODE_CLEAR, s_result); + ASSERT_EQ(check_gpg_error_2_err_code(err), GPG_ERR_NO_ERROR); + ASSERT_EQ(s_result->invalid_signers, nullptr); + + GpgVerifyResult v_result; + BypeArrayPtr sign_buff = nullptr; + err = BasicOperator::GetInstance(default_channel) + .Verify(*sign_out_data, sign_buff, v_result); + ASSERT_EQ(check_gpg_error_2_err_code(err), GPG_ERR_NO_ERROR); + ASSERT_NE(v_result->signatures, nullptr); + ASSERT_EQ(std::string(v_result->signatures->fpr), + "467F14220CE8DCF780CF4BAD8465C55B25C9B7D1"); + ASSERT_EQ(v_result->signatures->next, nullptr); +} + +TEST_F(GpgCoreTest, CoreEncryptSignDecrVerifyTest) { + auto encrpyt_key = GpgKeyGetter::GetInstance(default_channel) + .GetPubkey("467F14220CE8DCF780CF4BAD8465C55B25C9B7D1"); + auto sign_key = GpgKeyGetter::GetInstance(default_channel) + .GetKey("8933EB283A18995F45D61DAC021D89771B680FFB"); + // Question? + // ASSERT_FALSE(encrpyt_key.is_private_key()); + ASSERT_TRUE(sign_key.is_private_key()); + ASSERT_TRUE(sign_key.CanSignActual()); + ByteArray encrypt_text = "Hello GpgFrontend!"; + BypeArrayPtr encr_out_data; + GpgEncrResult e_result; + GpgSignResult s_result; + + std::vector<GpgKey> keys, sign_keys; + keys.push_back(std::move(encrpyt_key)); + sign_keys.push_back(std::move(sign_key)); + + auto err = BasicOperator::GetInstance(default_channel) + .EncryptSign(std::move(keys), std::move(sign_keys), + encrypt_text, encr_out_data, e_result, s_result); + ASSERT_EQ(check_gpg_error_2_err_code(err), GPG_ERR_NO_ERROR); + ASSERT_EQ(e_result->invalid_recipients, nullptr); + ASSERT_EQ(s_result->invalid_signers, nullptr); + + GpgDecrResult d_result; + GpgVerifyResult v_result; + BypeArrayPtr decr_out_data = nullptr; + err = BasicOperator::GetInstance(default_channel) + .DecryptVerify(*encr_out_data, decr_out_data, d_result, v_result); + ASSERT_EQ(check_gpg_error_2_err_code(err), GPG_ERR_NO_ERROR); + ASSERT_NE(d_result->recipients, nullptr); + ASSERT_EQ(std::string(d_result->recipients->keyid), "F89C95A05088CC93"); + ASSERT_EQ(*decr_out_data, encrypt_text); + ASSERT_NE(v_result->signatures, nullptr); + ASSERT_EQ(std::string(v_result->signatures->fpr), + "8933EB283A18995F45D61DAC021D89771B680FFB"); + ASSERT_EQ(v_result->signatures->next, nullptr); +} diff --git a/test/GpgCoreTestImportExport.cpp b/test/GpgCoreTestImportExport.cpp new file mode 100644 index 00000000..499e8503 --- /dev/null +++ b/test/GpgCoreTestImportExport.cpp @@ -0,0 +1,35 @@ +/** + * 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 "GpgFrontendTest.h" + +#include <string> +#include <vector> + +#include "gpg/GpgConstants.h" +#include "gpg/function/GpgKeyGetter.h" +#include "gpg/function/GpgKeyImportExportor.h" +#include "gpg/model/GpgKey.h" + +TEST_F(GpgCoreTest, CoreExportSecretTest) {}
\ No newline at end of file diff --git a/test/GpgCoreTest.cpp b/test/GpgCoreTestKeyModel.cpp index 7705e8b0..1d405cf4 100644 --- a/test/GpgCoreTest.cpp +++ b/test/GpgCoreTestKeyModel.cpp @@ -24,110 +24,17 @@ #include "GpgFrontendTest.h" -#include <gpg-error.h> -#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" -#include "gpg/function/GpgKeyImportExportor.h" -#include "gpg/function/GpgKeyOpera.h" - -TEST(GpgKeyTest, GpgCoreTest) {} -class GpgCoreTest : public ::testing::Test { - protected: - 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() { - DLOG(INFO) << "SetUp called"; - using namespace libconfig; - Config cfg; - ASSERT_NO_THROW(cfg.readFile(config_path.c_str())); - - const Setting& root = cfg.getRoot(); - ASSERT_TRUE(root.exists("independent_database")); - bool independent_database = true; - ASSERT_TRUE(root.lookupValue("independent_database", independent_database)); - - 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() {} - - private: - void dealing_private_keys() {} - - void configure_independent_database() {} -}; +// Should be used once and once-only +INITIALIZE_EASYLOGGINGPP TEST_F(GpgCoreTest, CoreInitTest) { - auto& ctx = GpgFrontend::GpgContext::GetInstance(1); - DLOG(INFO) << "CoreInitTest ctx DatabasePath " << ctx.GetInfo().DatabasePath; + auto& ctx = GpgFrontend::GpgContext::GetInstance(default_channel); auto& ctx_default = GpgFrontend::GpgContext::GetInstance(); - DLOG(INFO) << "CoreInitTest ctx_default DatabasePath " - << ctx_default.GetInfo().DatabasePath; ASSERT_TRUE(ctx.good()); + ASSERT_TRUE(ctx_default.good()); + ASSERT_EQ(ctx_default.GetInfo().DatabasePath, "default"); } TEST_F(GpgCoreTest, GpgDataTest) { @@ -137,14 +44,12 @@ TEST_F(GpgCoreTest, GpgDataTest) { GpgFrontend::GpgData data(data_buff.data(), data_buff.size()); auto out_buffer = data.Read2Buffer(); - LOG(INFO) << "in_buffer size " << data_buff.size(); - LOG(INFO) << "out_buffer size " << out_buffer->size(); ASSERT_EQ(out_buffer->size(), 64); } TEST_F(GpgCoreTest, GpgKeyTest) { - auto key = GpgFrontend::GpgKeyGetter::GetInstance(1).GetKey( - "9490795B78F8AFE9F93BD09281704859182661FB"); + auto key = GpgFrontend::GpgKeyGetter::GetInstance(default_channel) + .GetKey("9490795B78F8AFE9F93BD09281704859182661FB"); ASSERT_TRUE(key.good()); ASSERT_TRUE(key.is_private_key()); ASSERT_TRUE(key.has_master_key()); @@ -186,8 +91,8 @@ TEST_F(GpgCoreTest, GpgKeyTest) { } TEST_F(GpgCoreTest, GpgSubKeyTest) { - auto key = GpgFrontend::GpgKeyGetter::GetInstance(1).GetKey( - "9490795B78F8AFE9F93BD09281704859182661FB"); + auto key = GpgFrontend::GpgKeyGetter::GetInstance(default_channel) + .GetKey("9490795B78F8AFE9F93BD09281704859182661FB"); auto sub_keys = key.subKeys(); ASSERT_EQ(sub_keys->size(), 2); @@ -216,8 +121,8 @@ TEST_F(GpgCoreTest, GpgSubKeyTest) { } TEST_F(GpgCoreTest, GpgUIDTest) { - auto key = GpgFrontend::GpgKeyGetter::GetInstance(1).GetKey( - "9490795B78F8AFE9F93BD09281704859182661FB"); + auto key = GpgFrontend::GpgKeyGetter::GetInstance(default_channel) + .GetKey("9490795B78F8AFE9F93BD09281704859182661FB"); auto uids = key.uids(); ASSERT_EQ(uids->size(), 1); auto& uid = uids->front(); @@ -231,8 +136,8 @@ TEST_F(GpgCoreTest, GpgUIDTest) { } TEST_F(GpgCoreTest, GpgKeySignatureTest) { - auto key = GpgFrontend::GpgKeyGetter::GetInstance(1).GetKey( - "9490795B78F8AFE9F93BD09281704859182661FB"); + auto key = GpgFrontend::GpgKeyGetter::GetInstance(default_channel) + .GetKey("9490795B78F8AFE9F93BD09281704859182661FB"); auto uids = key.uids(); ASSERT_EQ(uids->size(), 1); auto& uid = uids->front(); @@ -255,17 +160,11 @@ TEST_F(GpgCoreTest, GpgKeySignatureTest) { } TEST_F(GpgCoreTest, GpgKeyGetterTest) { - auto key = GpgFrontend::GpgKeyGetter::GetInstance(1).GetKey( - "9490795B78F8AFE9F93BD09281704859182661FB"); + auto key = GpgFrontend::GpgKeyGetter::GetInstance(default_channel) + .GetKey("9490795B78F8AFE9F93BD09281704859182661FB"); ASSERT_TRUE(key.good()); - auto keys = GpgFrontend::GpgKeyGetter::GetInstance(1).FetchKey(); - ASSERT_GE(keys->size(), 1); - + auto keys = + GpgFrontend::GpgKeyGetter::GetInstance(default_channel).FetchKey(); + ASSERT_GE(keys->size(), secret_keys_.size()); ASSERT_TRUE(find(keys->begin(), keys->end(), key) != keys->end()); } - -TEST_F(GpgCoreTest, GpgKeyDeleteTest) { - // GpgFrontend::GpgKeyOpera::GetInstance().DeleteKeys( - // std::move(std::make_unique<std::vector<std::string>>( - // 1, "9490795B78F8AFE9F93BD09281704859182661FB"))); -} diff --git a/test/GpgFrontendTest.h b/test/GpgFrontendTest.h index b683934f..f7ffb72f 100644 --- a/test/GpgFrontendTest.h +++ b/test/GpgFrontendTest.h @@ -27,6 +27,103 @@ #include <easyloggingpp/easylogging++.h> -INITIALIZE_EASYLOGGINGPP +#include <gpg-error.h> +#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 <memory> +#include <string> +#include <vector> -#endif // _GPGFRONTENDTEST_H +#include "gpg/GpgConstants.h" +#include "gpg/function/GpgKeyImportExportor.h" + +class GpgCoreTest : public ::testing::Test { + protected: + // Secret Keys Imported + std::vector<GpgFrontend::StdBypeArrayPtr> secret_keys_; + + // Program Location + boost::filesystem::path parent_path = + boost::dll::program_location().parent_path(); + + // Configure File Location + boost::filesystem::path config_path = parent_path / "conf" / "core.cfg"; + + // Data File Directory Location + boost::filesystem::path data_path; + + int default_channel = 0; + + GpgCoreTest() = default; + + virtual ~GpgCoreTest() = default; + + virtual void SetUp() { + using namespace libconfig; + Config cfg; + ASSERT_NO_THROW(cfg.readFile(config_path.c_str())); + Setting& root = cfg.getRoot(); + + if (root.exists("data_path")) { + std::string relative_data_path; + root.lookupValue("data_path", relative_data_path); + data_path = parent_path / relative_data_path; + }; + + configure_independent_database(root); + + dealing_private_keys(root); + import_data(); + } + + virtual void TearDown() {} + + private: + void import_data() { + GpgFrontend::GpgContext::GetInstance(default_channel) + .SetPassphraseCb(GpgFrontend::GpgContext::test_passphrase_cb); + for (auto& secret_key : secret_keys_) { + GpgFrontend::GpgKeyImportExportor::GetInstance(default_channel) + .ImportKey(std::move(secret_key)); + } + } + void dealing_private_keys(const libconfig::Setting& root) { + if (root.exists("load_keys.private_keys")) { + auto& private_keys = root.lookup("load_keys.private_keys"); + for (auto it = private_keys.begin(); it != private_keys.end(); it++) { + if (it->exists("filename")) { + std::string filename; + it->lookupValue("filename", filename); + auto data_file_path = data_path / filename; + std::string data = + GpgFrontend::read_all_data_in_file(data_file_path.string()); + secret_keys_.push_back(std::make_unique<std::string>(data)); + } + } + } + } + + void configure_independent_database(const libconfig::Setting& root) { + bool independent_database = false; + if (root.exists("independent_database")) { + root.lookupValue("independent_database", independent_database); + if (independent_database && root.exists("independent_db_path")) { + default_channel = 1; + std::string relative_db_path; + 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); + } + GpgFrontend::GpgContext::CreateInstance( + 1, + std::make_unique<GpgFrontend::GpgContext>(true, db_path.c_str())); + } + } + } +}; + +#endif // _GPGFRONTENDTEST_H diff --git a/test/conf/core.cfg b/test/conf/core.cfg index 4129d39f..69395963 100644 --- a/test/conf/core.cfg +++ b/test/conf/core.cfg @@ -5,8 +5,20 @@ independent_db_path = "db" data_path = "data" load_keys = { - private_keys = ({ - filename = "pv1.key"; - md5 = ""; - }); + private_keys = ( + { + filename = "pv1.key"; + md5 = "1d6ceb1aa836b582fa3750cb162ce90c"; + },{ + filename = "pv2.key"; + md5 = "ce52f1557a1d7e74c4f157fdf8f56d41"; + },{ + filename = "pv3.key"; + md5 = "ab7bc39ccb46ccdd71867a391f2d2306"; + }, + { + filename = "pv4.key"; + md5 = "c88ff29f7c75fa118776a62313035442"; + } + ); };
\ No newline at end of file diff --git a/test/data/pv2.key b/test/data/pv2.key new file mode 100644 index 00000000..54bea6f5 --- /dev/null +++ b/test/data/pv2.key @@ -0,0 +1,41 @@ +-----BEGIN PGP PRIVATE KEY BLOCK----- + +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 +VFT4TeJBu/bR1d3DxY8XrO5J8zc= +=7sPJ +-----END PGP PRIVATE KEY BLOCK-----
\ No newline at end of file diff --git a/test/data/pv3.key b/test/data/pv3.key new file mode 100644 index 00000000..6162ceef --- /dev/null +++ b/test/data/pv3.key @@ -0,0 +1,106 @@ +-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+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
+s68=
+=u5ok
+-----END PGP PRIVATE KEY BLOCK-----
diff --git a/test/data/pv4.key b/test/data/pv4.key new file mode 100644 index 00000000..67edc9e1 --- /dev/null +++ b/test/data/pv4.key @@ -0,0 +1,82 @@ +-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+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
+T15m3mvre/E=
+=h5NI
+-----END PGP PRIVATE KEY BLOCK-----
|