diff options
-rw-r--r-- | src/core/function/gpg/GpgKeyManager.cpp | 152 | ||||
-rw-r--r-- | src/core/function/gpg/GpgKeyManager.h | 60 | ||||
-rw-r--r-- | src/core/model/GpgKey.cpp | 12 | ||||
-rw-r--r-- | src/ui/dialog/keypair_details/KeyPairDetailTab.cpp | 23 | ||||
-rw-r--r-- | src/ui/dialog/keypair_details/KeyPairDetailTab.h | 1 | ||||
-rw-r--r-- | src/ui/dialog/keypair_details/KeyPairOperaTab.cpp | 49 | ||||
-rw-r--r-- | src/ui/dialog/keypair_details/KeyPairOperaTab.h | 13 | ||||
-rw-r--r-- | src/ui/widgets/KeyList.cpp | 2 |
8 files changed, 296 insertions, 16 deletions
diff --git a/src/core/function/gpg/GpgKeyManager.cpp b/src/core/function/gpg/GpgKeyManager.cpp index 050a8238..3e87f0dd 100644 --- a/src/core/function/gpg/GpgKeyManager.cpp +++ b/src/core/function/gpg/GpgKeyManager.cpp @@ -28,11 +28,14 @@ #include "GpgKeyManager.h" +#include <boost/algorithm/string.hpp> #include <boost/date_time/posix_time/conversion.hpp> +#include <memory> #include <string> #include "GpgBasicOperator.h" #include "GpgKeyGetter.h" +#include "spdlog/spdlog.h" GpgFrontend::GpgKeyManager::GpgKeyManager(int channel) : SingletonFunctionObject<GpgKeyManager>(channel) {} @@ -93,3 +96,152 @@ bool GpgFrontend::GpgKeyManager::SetExpire( return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR; } + +bool GpgFrontend::GpgKeyManager::SetOwnerTrustLevel(const GpgKey& key, + int trust_level) { + if (trust_level < 0 || trust_level > 5) { + SPDLOG_ERROR("illegal owner trust level: {}", trust_level); + } + + AutomatonNextStateHandler next_state_handler = + [](AutomatonState state, std::string status, std::string args) { + SPDLOG_DEBUG("next_state_handler state: {}, gpg_status: {}, args: {}", + state, status, args); + std::vector<std::string> tokens; + boost::split(tokens, args, boost::is_any_of(" ")); + + switch (state) { + case START: + if (status == "GET_LINE" && args == "keyedit.prompt") + return COMMAND; + return ERROR; + case COMMAND: + if (status == "GET_LINE" && args == "edit_ownertrust.value") { + return VALUE; + } + return ERROR; + case VALUE: + if (status == "GET_LINE" && args == "keyedit.prompt") { + return QUIT; + } else if (status == "GET_BOOL" && + args == "edit_ownertrust.set_ultimate.okay") { + return REALLY_ULTIMATE; + } + return ERROR; + case REALLY_ULTIMATE: + if (status == "GET_LINE" && args == "keyedit.prompt") { + return QUIT; + } + return ERROR; + case QUIT: + if (status == "GET_LINE" && args == "keyedit.save.okay") { + return SAVE; + } + return ERROR; + case ERROR: + if (status == "GET_LINE" && args == "keyedit.prompt") { + return QUIT; + } + return ERROR; + default: + return ERROR; + }; + }; + + AutomatonActionHandler action_handler = + [trust_level](AutomatonHandelStruct& handler, AutomatonState state) { + SPDLOG_DEBUG("action_handler state: {}", state); + switch (state) { + case COMMAND: + return std::string("trust"); + case VALUE: + handler.SetSuccess(true); + return std::to_string(trust_level); + case REALLY_ULTIMATE: + handler.SetSuccess(true); + return std::string("Y"); + case QUIT: + return std::string("quit"); + case SAVE: + handler.SetSuccess(true); + return std::string("Y"); + case START: + case ERROR: + return std::string(""); + default: + return std::string(""); + } + return std::string(""); + }; + + auto key_fpr = key.GetFingerprint(); + AutomatonHandelStruct handel_struct(key_fpr); + handel_struct.SetHandler(next_state_handler, action_handler); + + GpgData data_out; + + auto err = gpgme_op_interact(ctx_, gpgme_key_t(key), 0, + GpgKeyManager::interactor_cb_fnc, + (void*)&handel_struct, data_out); + if (err != GPG_ERR_NO_ERROR) { + SPDLOG_ERROR("fail to set owner trust level {} to key {}, err: {}", + trust_level, key.GetId(), gpgme_strerror(err)); + } + + return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR && + handel_struct.Success(); +} + +gpgme_error_t GpgFrontend::GpgKeyManager::interactor_cb_fnc(void* handle, + const char* status, + const char* args, + int fd) { + auto handle_struct = static_cast<AutomatonHandelStruct*>(handle); + std::string status_s = status; + std::string args_s = args; + SPDLOG_DEBUG("cb start status: {}, args: {}, fd: {}, handle struct state: {}", + status_s, args_s, fd, handle_struct->CuurentStatus()); + + if (status_s == "KEY_CONSIDERED") { + std::vector<std::string> tokens; + boost::split(tokens, args, boost::is_any_of(" ")); + + if (tokens.empty() || tokens[0] != handle_struct->KeyFpr()) { + SPDLOG_ERROR("handle struct key fpr {} mismatch token: {}, exit...", + handle_struct->KeyFpr(), tokens[0]); + return -1; + } + + return 0; + } + + if (status_s == "GOT_IT" || status_s.empty()) { + SPDLOG_DEBUG("status GOT_IT, continue..."); + return 0; + } + + AutomatonState next_state = handle_struct->NextState(status_s, args_s); + if (next_state == ERROR) { + SPDLOG_DEBUG("handle struct next state caught error, skipping..."); + return GPG_ERR_FALSE; + } + + if (next_state == SAVE) { + handle_struct->SetSuccess(true); + } + + // set state and preform action + handle_struct->SetStatus(next_state); + Command cmd = handle_struct->Action(); + SPDLOG_DEBUG("handle struct action done, next state: {}, action cmd: {}", + next_state, cmd); + if (!cmd.empty()) { + gpgme_io_write(fd, cmd.c_str(), cmd.size()); + gpgme_io_write(fd, "\n", 1); + } else if (status_s == "GET_LINE") { + // avoid trapping in this state + return GPG_ERR_FALSE; + } + + return 0; +}
\ No newline at end of file diff --git a/src/core/function/gpg/GpgKeyManager.h b/src/core/function/gpg/GpgKeyManager.h index 22738594..f967dee7 100644 --- a/src/core/function/gpg/GpgKeyManager.h +++ b/src/core/function/gpg/GpgKeyManager.h @@ -29,6 +29,9 @@ #ifndef GPGFRONTEND_ZH_CN_TS_GPGKEYMANAGER_H #define GPGFRONTEND_ZH_CN_TS_GPGKEYMANAGER_H +#include <functional> +#include <string> + #include "core/GpgContext.h" #include "core/GpgFunctionObject.h" #include "core/GpgModel.h" @@ -83,7 +86,64 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyManager bool SetExpire(const GpgKey& key, std::unique_ptr<GpgSubKey>& subkey, std::unique_ptr<boost::posix_time::ptime>& expires); + /** + * @brief + * + * @return + */ + bool SetOwnerTrustLevel(const GpgKey& key, int trust_level); + private: + static gpgme_error_t interactor_cb_fnc(void* handle, const char* status, + const char* args, int fd); + + using Command = std::string; + using AutomatonState = enum { + START, + COMMAND, + VALUE, + REALLY_ULTIMATE, + SAVE, + ERROR, + QUIT, + }; + + struct AutomatonHandelStruct; + + using AutomatonActionHandler = + std::function<Command(AutomatonHandelStruct&, AutomatonState)>; + using AutomatonNextStateHandler = + std::function<AutomatonState(AutomatonState, std::string, std::string)>; + + struct AutomatonHandelStruct { + void SetStatus(AutomatonState next_state) { current_state_ = next_state; } + AutomatonState CuurentStatus() { return current_state_; } + void SetHandler(AutomatonNextStateHandler next_state_handler, + AutomatonActionHandler action_handler) { + next_state_handler_ = next_state_handler; + action_handler_ = action_handler; + } + AutomatonState NextState(std::string gpg_status, std::string args) { + return next_state_handler_(current_state_, gpg_status, args); + } + Command Action() { return action_handler_(*this, current_state_); } + + void SetSuccess(bool success) { success_ = success; } + + bool Success() { return success_; } + + std::string KeyFpr() { return key_fpr_; } + + AutomatonHandelStruct(std::string key_fpr) : key_fpr_(key_fpr) {} + + private: + AutomatonState current_state_ = START; + AutomatonNextStateHandler next_state_handler_; + AutomatonActionHandler action_handler_; + bool success_ = false; + std::string key_fpr_; + }; + GpgContext& ctx_ = GpgContext::GetInstance(SingletonFunctionObject::GetChannel()); ///< }; diff --git a/src/core/model/GpgKey.cpp b/src/core/model/GpgKey.cpp index 4716d9cc..e2e7df6e 100644 --- a/src/core/model/GpgKey.cpp +++ b/src/core/model/GpgKey.cpp @@ -78,17 +78,17 @@ std::string GpgFrontend::GpgKey::GetProtocol() const { std::string GpgFrontend::GpgKey::GetOwnerTrust() const { switch (key_ref_->owner_trust) { case GPGME_VALIDITY_UNKNOWN: - return "Unknown"; + return _("Unknown"); case GPGME_VALIDITY_UNDEFINED: - return "Undefined"; + return _("Undefined"); case GPGME_VALIDITY_NEVER: - return "Never"; + return _("Never"); case GPGME_VALIDITY_MARGINAL: - return "Marginal"; + return _("Marginal"); case GPGME_VALIDITY_FULL: - return "FULL"; + return _("Full"); case GPGME_VALIDITY_ULTIMATE: - return "Ultimate"; + return _("Ultimate"); } return "Invalid"; } diff --git a/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp b/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp index 2785603b..578e3279 100644 --- a/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp +++ b/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp @@ -56,6 +56,7 @@ KeyPairDetailTab::KeyPairDetailTab(const std::string& key_id, QWidget* parent) usage_var_label_ = new QLabel(); actual_usage_var_label_ = new QLabel(); + owner_trust_var_label_ = new QLabel(); key_size_var_label_ = new QLabel(); expire_var_label_ = new QLabel(); created_var_label_ = new QLabel(); @@ -79,13 +80,14 @@ KeyPairDetailTab::KeyPairDetailTab(const std::string& key_id, QWidget* parent) vboxKD->addWidget(new QLabel(QString(_("Key Size")) + ": "), 2, 0); vboxKD->addWidget(new QLabel(QString(_("Nominal Usage")) + ": "), 3, 0); vboxKD->addWidget(new QLabel(QString(_("Actual Usage")) + ": "), 4, 0); + vboxKD->addWidget(new QLabel(QString(_("Owner Trust Level")) + ": "), 5, 0); vboxKD->addWidget(new QLabel(QString(_("Create Date (Local Time)")) + ": "), - 5, 0); - vboxKD->addWidget(new QLabel(QString(_("Expires on (Local Time)")) + ": "), 6, + 6, 0); + vboxKD->addWidget(new QLabel(QString(_("Expires on (Local Time)")) + ": "), 7, 0); vboxKD->addWidget(new QLabel(QString(_("Last Update (Local Time)")) + ": "), - 7, 0); - vboxKD->addWidget(new QLabel(QString(_("Primary Key Existence")) + ": "), 8, + 8, 0); + vboxKD->addWidget(new QLabel(QString(_("Primary Key Existence")) + ": "), 9, 0); key_id_var_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); @@ -94,10 +96,11 @@ KeyPairDetailTab::KeyPairDetailTab(const std::string& key_id, QWidget* parent) vboxKD->addWidget(key_size_var_label_, 2, 1, 1, 2); vboxKD->addWidget(usage_var_label_, 3, 1, 1, 2); vboxKD->addWidget(actual_usage_var_label_, 4, 1, 1, 2); - vboxKD->addWidget(created_var_label_, 5, 1, 1, 2); - vboxKD->addWidget(expire_var_label_, 6, 1, 1, 2); - vboxKD->addWidget(last_update_var_label_, 7, 1, 1, 2); - vboxKD->addWidget(primary_key_exist_var_label_, 8, 1, 1, 2); + vboxKD->addWidget(owner_trust_var_label_, 5, 1, 1, 2); + vboxKD->addWidget(created_var_label_, 6, 1, 1, 2); + vboxKD->addWidget(expire_var_label_, 7, 1, 1, 2); + vboxKD->addWidget(last_update_var_label_, 8, 1, 1, 2); + vboxKD->addWidget(primary_key_exist_var_label_, 9, 1, 1, 2); auto* copyKeyIdButton = new QPushButton(_("Copy")); copyKeyIdButton->setFlat(true); @@ -222,7 +225,9 @@ void KeyPairDetailTab::slot_refresh_key_info() { if (key_.IsHasActualAuthenticationCapability()) actual_usage_steam << _("Auth") << " "; - actual_usage_var_label_->setText(actual_usage_steam.str().c_str()); + actual_usage_var_label_->setText( + QString::fromStdString(actual_usage_steam.str())); + owner_trust_var_label_->setText(QString::fromStdString(key_.GetOwnerTrust())); std::string key_size_val, key_expire_val, key_create_time_val, key_algo_val, key_last_update_val; diff --git a/src/ui/dialog/keypair_details/KeyPairDetailTab.h b/src/ui/dialog/keypair_details/KeyPairDetailTab.h index 91ccdab8..efa3269c 100644 --- a/src/ui/dialog/keypair_details/KeyPairDetailTab.h +++ b/src/ui/dialog/keypair_details/KeyPairDetailTab.h @@ -79,6 +79,7 @@ class KeyPairDetailTab : public QWidget { QLabel* usage_var_label_; QLabel* actual_usage_var_label_; QLabel* primary_key_exist_var_label_; + QLabel* owner_trust_var_label_; QLabel* icon_label_; ///< QLabel* exp_label_; ///< diff --git a/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp b/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp index 9be77923..34bd8534 100644 --- a/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp +++ b/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp @@ -29,6 +29,7 @@ #include "KeySetExpireDateDialog.h" #include "core/function/GlobalSettingStation.h" #include "core/function/gpg/GpgKeyImportExporter.h" +#include "core/function/gpg/GpgKeyManager.h" #include "core/function/gpg/GpgKeyOpera.h" #include "ui/SignalStation.h" #include "ui/UserInterfaceUtils.h" @@ -105,13 +106,25 @@ KeyPairOperaTab::KeyPairOperaTab(const std::string& key_id, QWidget* parent) connect(modify_tofu_button, &QPushButton::clicked, this, &KeyPairOperaTab::slot_modify_tofu_policy); + auto* set_owner_trust_level_button = + new QPushButton(_("Set Owner Trust Level")); + connect(set_owner_trust_level_button, &QPushButton::clicked, this, + &KeyPairOperaTab::slot_set_owner_trust_level); + vbox_p_k->addLayout(advance_h_box_layout); opera_key_box->setLayout(vbox_p_k); m_vbox->addWidget(opera_key_box); + // modify owner trust of public key + if (!m_key_.IsPrivateKey()) vbox_p_k->addWidget(set_owner_trust_level_button); vbox_p_k->addWidget(modify_tofu_button); m_vbox->addStretch(0); setLayout(m_vbox); + + // set up signal + connect(this, &KeyPairOperaTab::SignalKeyDatabaseRefresh, + SignalStation::GetInstance(), + &SignalStation::SignalKeyDatabaseRefresh); } void KeyPairOperaTab::CreateOperaMenu() { @@ -389,4 +402,40 @@ void KeyPairOperaTab::slot_modify_tofu_policy() { } } +void KeyPairOperaTab::slot_set_owner_trust_level() { + QStringList items; + + items << _("Ultimate") << _("Full") << _("Marginal") << _("Never") + << _("Undefined") << _("Unknown"); + + bool ok; + QString item = + QInputDialog::getItem(this, _("Modify Owner Trust Level"), + _("Trust for the Key Pair:"), items, 0, false, &ok); + if (ok && !item.isEmpty()) { + SPDLOG_DEBUG("selected policy: {}", item.toStdString()); + int trust_level = 0; // Unknown Level + if (item == _("Ultimate")) { + trust_level = 5; + } else if (item == _("Full")) { + trust_level = 4; + } else if (item == _("Marginal")) { + trust_level = 3; + } else if (item == _("Never")) { + trust_level = 2; + } else if (item == _("Undefined")) { + trust_level = 1; + } + bool status = + GpgKeyManager::GetInstance().SetOwnerTrustLevel(m_key_, trust_level); + if (!status) { + QMessageBox::critical(this, _("Failed"), + QString(_("Modify Owner Trust Level failed."))); + } else { + // update key database and refresh ui + emit SignalKeyDatabaseRefresh(); + } + } +} + } // namespace GpgFrontend::UI diff --git a/src/ui/dialog/keypair_details/KeyPairOperaTab.h b/src/ui/dialog/keypair_details/KeyPairOperaTab.h index af6b1eee..0c4a7916 100644 --- a/src/ui/dialog/keypair_details/KeyPairOperaTab.h +++ b/src/ui/dialog/keypair_details/KeyPairOperaTab.h @@ -48,6 +48,13 @@ class KeyPairOperaTab : public QWidget { */ void CreateOperaMenu(); + signals: + /** + * @brief + * + */ + void SignalKeyDatabaseRefresh(); + private slots: /** @@ -103,6 +110,12 @@ class KeyPairOperaTab : public QWidget { */ void slot_modify_tofu_policy(); + /** + * @brief + * + */ + void slot_set_owner_trust_level(); + private: GpgKey m_key_; ///< QMenu* key_server_opera_menu_{}; ///< diff --git a/src/ui/widgets/KeyList.cpp b/src/ui/widgets/KeyList.cpp index 2d4c925a..670644a8 100644 --- a/src/ui/widgets/KeyList.cpp +++ b/src/ui/widgets/KeyList.cpp @@ -155,7 +155,7 @@ void KeyList::AddListGroupTab( QStringList labels; labels << _("Select") << _("Type") << _("Name") << _("Email Address") - << _("Usage") << _("Validity") << _("Finger Print"); + << _("Usage") << _("Trust") << _("Finger Print"); key_list->setHorizontalHeaderLabels(labels); key_list->horizontalHeader()->setStretchLastSection(false); |