diff options
author | Saturneric <[email protected]> | 2023-07-12 15:46:44 +0000 |
---|---|---|
committer | Saturneric <[email protected]> | 2023-07-12 15:46:44 +0000 |
commit | cee9909c2b705e20564d529792055d070167c0a7 (patch) | |
tree | 70f489024e62c6aacb1c1cc51f59f110e9dcb6f5 /src/core/function/gpg | |
parent | fix: modify the ui file of FilePage (diff) | |
download | GpgFrontend-cee9909c2b705e20564d529792055d070167c0a7.tar.gz GpgFrontend-cee9909c2b705e20564d529792055d070167c0a7.zip |
feat: support owner trust level settings of gpg key
Diffstat (limited to 'src/core/function/gpg')
-rw-r--r-- | src/core/function/gpg/GpgKeyManager.cpp | 152 | ||||
-rw-r--r-- | src/core/function/gpg/GpgKeyManager.h | 60 |
2 files changed, 212 insertions, 0 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()); ///< }; |