aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSaturneric <[email protected]>2023-07-12 15:46:44 +0000
committerSaturneric <[email protected]>2023-07-12 15:46:44 +0000
commitcee9909c2b705e20564d529792055d070167c0a7 (patch)
tree70f489024e62c6aacb1c1cc51f59f110e9dcb6f5
parentfix: modify the ui file of FilePage (diff)
downloadGpgFrontend-cee9909c2b705e20564d529792055d070167c0a7.tar.gz
GpgFrontend-cee9909c2b705e20564d529792055d070167c0a7.zip
feat: support owner trust level settings of gpg key
-rw-r--r--src/core/function/gpg/GpgKeyManager.cpp152
-rw-r--r--src/core/function/gpg/GpgKeyManager.h60
-rw-r--r--src/core/model/GpgKey.cpp12
-rw-r--r--src/ui/dialog/keypair_details/KeyPairDetailTab.cpp23
-rw-r--r--src/ui/dialog/keypair_details/KeyPairDetailTab.h1
-rw-r--r--src/ui/dialog/keypair_details/KeyPairOperaTab.cpp49
-rw-r--r--src/ui/dialog/keypair_details/KeyPairOperaTab.h13
-rw-r--r--src/ui/widgets/KeyList.cpp2
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);