aboutsummaryrefslogtreecommitdiffstats
path: root/src/core/function
diff options
context:
space:
mode:
authorsaturneric <[email protected]>2024-11-19 15:00:56 +0000
committersaturneric <[email protected]>2024-11-19 15:00:56 +0000
commit5b883eebb6992e00a8979000a64e72ff1aae9432 (patch)
tree4a52c8620e3cb02d2ca3d4b2112c553239ada5bb /src/core/function
parentfeat: add delete subkey function (diff)
downloadGpgFrontend-5b883eebb6992e00a8979000a64e72ff1aae9432.tar.gz
GpgFrontend-5b883eebb6992e00a8979000a64e72ff1aae9432.zip
feat: add revoke subkey function
Diffstat (limited to 'src/core/function')
-rw-r--r--src/core/function/gpg/GpgKeyManager.cpp237
-rw-r--r--src/core/function/gpg/GpgKeyManager.h13
2 files changed, 195 insertions, 55 deletions
diff --git a/src/core/function/gpg/GpgKeyManager.cpp b/src/core/function/gpg/GpgKeyManager.cpp
index bd52c341..753b668f 100644
--- a/src/core/function/gpg/GpgKeyManager.cpp
+++ b/src/core/function/gpg/GpgKeyManager.cpp
@@ -36,6 +36,64 @@
GpgFrontend::GpgKeyManager::GpgKeyManager(int channel)
: SingletonFunctionObject<GpgKeyManager>(channel) {}
+auto GpgFrontend::GpgKeyManager::interactor_cb_fnc(void* handle,
+ const char* status,
+ const char* args,
+ int fd) -> gpgme_error_t {
+ auto* handle_struct = static_cast<AutomatonHandelStruct*>(handle);
+ QString status_s = status;
+ QString args_s = args;
+
+ if (status_s == "KEY_CONSIDERED") {
+ auto tokens = QString(args).split(' ');
+
+ if (tokens.empty() || tokens[0] != handle_struct->KeyFpr()) {
+ LOG_W() << "handle struct key fpr " << handle_struct->KeyFpr()
+ << "mismatch token: " << tokens[0] << ", exit...";
+
+ return -1;
+ }
+
+ return 0;
+ }
+
+ if (status_s == "GOT_IT" || status_s.isEmpty()) {
+ FLOG_D("gpg reply is GOT_IT, continue...");
+ return 0;
+ }
+
+ LOG_D() << "current state" << handle_struct->CurrentStatus()
+ << "gpg status: " << status_s << ", args: " << args_s;
+
+ AutomatonState next_state = handle_struct->NextState(status_s, args_s);
+ if (next_state == AS_ERROR) {
+ FLOG_D("handle struct next state caught error, abort...");
+ return -1;
+ }
+ LOG_D() << "next state" << next_state;
+
+ if (next_state == AS_SAVE) {
+ handle_struct->SetSuccess(true);
+ }
+
+ // set state and preform action
+ handle_struct->SetStatus(next_state);
+ Command cmd = handle_struct->Action();
+
+ LOG_D() << "next action, cmd:" << cmd;
+
+ if (!cmd.isEmpty()) {
+ auto btye_array = cmd.toUtf8();
+ gpgme_io_write(fd, btye_array, btye_array.size());
+ gpgme_io_write(fd, "\n", 1);
+ } else if (status_s == "GET_LINE") {
+ // avoid trapping in this state
+ return GPG_ERR_FALSE;
+ }
+
+ return 0;
+}
+
auto GpgFrontend::GpgKeyManager::SignKey(
const GpgFrontend::GpgKey& target, GpgFrontend::KeyArgsList& keys,
const QString& uid, const std::unique_ptr<QDateTime>& expires) -> bool {
@@ -179,69 +237,110 @@ auto GpgFrontend::GpgKeyManager::SetOwnerTrustLevel(const GpgKey& key,
return CheckGpgError(err) == GPG_ERR_NO_ERROR && handel_struct.Success();
}
-auto GpgFrontend::GpgKeyManager::interactor_cb_fnc(void* handle,
- const char* status,
- const char* args,
- int fd) -> gpgme_error_t {
- auto* handle_struct = static_cast<AutomatonHandelStruct*>(handle);
- QString status_s = status;
- QString args_s = args;
-
- if (status_s == "KEY_CONSIDERED") {
- auto tokens = QString(args).split(' ');
-
- if (tokens.empty() || tokens[0] != handle_struct->KeyFpr()) {
- LOG_W() << "handle struct key fpr " << handle_struct->KeyFpr()
- << "mismatch token: " << tokens[0] << ", exit...";
-
- return -1;
- }
-
- return 0;
- }
-
- if (status_s == "GOT_IT" || status_s.isEmpty()) {
- FLOG_D("status GOT_IT, continue...");
- return 0;
+auto GpgFrontend::GpgKeyManager::DeleteSubkey(const GpgKey& key,
+ int subkey_index) -> bool {
+ if (subkey_index < 0 || subkey_index >= key.GetSubKeys()->size()) {
+ LOG_W() << "illegal subkey index: " << subkey_index;
}
- LOG_D() << "current state" << handle_struct->CurrentStatus()
- << "gpg status: " << status_s << ", args: " << args_s;
-
- AutomatonState next_state = handle_struct->NextState(status_s, args_s);
- if (next_state == AS_ERROR) {
- FLOG_D("handle struct next state caught error, abort...");
- return -1;
- }
- LOG_D() << "next state" << next_state;
+ AutomatonNextStateHandler next_state_handler =
+ [](AutomatonState state, QString status, QString args) {
+ auto tokens = args.split(' ');
- if (next_state == AS_SAVE) {
- handle_struct->SetSuccess(true);
- }
+ switch (state) {
+ case AS_START:
+ if (status == "GET_LINE" && args == "keyedit.prompt") {
+ return AS_SELECT;
+ }
+ return AS_ERROR;
+ case AS_SELECT:
+ if (status == "GET_LINE" && args == "keyedit.prompt") {
+ return AS_COMMAND;
+ }
+ return AS_ERROR;
+ case AS_COMMAND:
+ if (status == "GET_LINE" && args == "keyedit.prompt") {
+ return AS_QUIT;
+ } else if (status == "GET_BOOL" &&
+ args == "keyedit.remove.subkey.okay") {
+ return AS_REALLY_ULTIMATE;
+ }
+ return AS_ERROR;
+ case AS_REALLY_ULTIMATE:
+ if (status == "GET_LINE" && args == "keyedit.prompt") {
+ return AS_QUIT;
+ }
+ return AS_ERROR;
+ case AS_QUIT:
+ if (status == "GET_BOOL" && args == "keyedit.save.okay") {
+ return AS_SAVE;
+ }
+ return AS_ERROR;
+ case AS_ERROR:
+ if (status == "GET_LINE" && args == "keyedit.prompt") {
+ return AS_QUIT;
+ }
+ return AS_ERROR;
+ default:
+ return AS_ERROR;
+ };
+ };
- // set state and preform action
- handle_struct->SetStatus(next_state);
- Command cmd = handle_struct->Action();
+ AutomatonActionHandler action_handler =
+ [subkey_index](AutomatonHandelStruct& handler, AutomatonState state) {
+ switch (state) {
+ case AS_SELECT:
+ return QString("key %1").arg(subkey_index);
+ case AS_COMMAND:
+ return QString("delkey");
+ case AS_REALLY_ULTIMATE:
+ handler.SetSuccess(true);
+ return QString("Y");
+ case AS_QUIT:
+ return QString("quit");
+ case AS_SAVE:
+ handler.SetSuccess(true);
+ return QString("Y");
+ case AS_START:
+ case AS_ERROR:
+ return QString("");
+ default:
+ return QString("");
+ }
+ return QString("");
+ };
- LOG_D() << "next action, cmd:" << cmd;
+ auto key_fpr = key.GetFingerprint();
+ AutomatonHandelStruct handel_struct(key_fpr);
+ handel_struct.SetHandler(next_state_handler, action_handler);
- if (!cmd.isEmpty()) {
- auto btye_array = cmd.toUtf8();
- gpgme_io_write(fd, btye_array, btye_array.size());
- gpgme_io_write(fd, "\n", 1);
- } else if (status_s == "GET_LINE") {
- // avoid trapping in this state
- return GPG_ERR_FALSE;
- }
+ GpgData data_out;
- return 0;
+ auto err =
+ gpgme_op_interact(ctx_.DefaultContext(), static_cast<gpgme_key_t>(key), 0,
+ GpgKeyManager::interactor_cb_fnc,
+ static_cast<void*>(&handel_struct), data_out);
+ return CheckGpgError(err) == GPG_ERR_NO_ERROR && handel_struct.Success();
}
-auto GpgFrontend::GpgKeyManager::DeleteSubkey(const GpgKey& key,
- int subkey_index) -> bool {
+
+auto GpgFrontend::GpgKeyManager::RevokeSubkey(
+ const GpgKey& key, int subkey_index, int reason_code,
+ const QString& reason_text) -> bool {
if (subkey_index < 0 || subkey_index >= key.GetSubKeys()->size()) {
LOG_W() << "illegal subkey index: " << subkey_index;
}
+ // dealing with reason text
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 4)
+ auto reason_text_lines =
+ GpgFrontend::SecureCreateSharedObject<QList<QString>>(
+ reason_text.split('\n', Qt::SkipEmptyParts).toVector());
+#else
+ auto reason_text_lines =
+ GpgFrontend::SecureCreateSharedObject<QVector<QString>>(
+ reason_text.split('\n', Qt::SkipEmptyParts).toVector());
+#endif
+
AutomatonNextStateHandler next_state_handler =
[](AutomatonState state, QString status, QString args) {
auto tokens = args.split(' ');
@@ -261,13 +360,35 @@ auto GpgFrontend::GpgKeyManager::DeleteSubkey(const GpgKey& key,
if (status == "GET_LINE" && args == "keyedit.prompt") {
return AS_QUIT;
} else if (status == "GET_BOOL" &&
- args == "keyedit.remove.subkey.okay") {
+ args == "keyedit.revoke.subkey.okay") {
+ return AS_REALLY_ULTIMATE;
+ }
+ return AS_ERROR;
+ case AS_REASON_CODE:
+ if (status == "GET_LINE" && args == "keyedit.prompt") {
+ return AS_QUIT;
+ } else if (status == "GET_LINE" &&
+ args == "ask_revocation_reason.text") {
+ return AS_REASON_TEXT;
+ }
+ return AS_ERROR;
+ case AS_REASON_TEXT:
+ if (status == "GET_LINE" && args == "keyedit.prompt") {
+ return AS_QUIT;
+ } else if (status == "GET_LINE" &&
+ args == "ask_revocation_reason.text") {
+ return AS_REASON_TEXT;
+ } else if (status == "GET_BOOL" &&
+ args == "ask_revocation_reason.okay") {
return AS_REALLY_ULTIMATE;
}
return AS_ERROR;
case AS_REALLY_ULTIMATE:
if (status == "GET_LINE" && args == "keyedit.prompt") {
return AS_QUIT;
+ } else if (status == "GET_LINE" &&
+ args == "ask_revocation_reason.code") {
+ return AS_REASON_CODE;
}
return AS_ERROR;
case AS_QUIT:
@@ -286,14 +407,20 @@ auto GpgFrontend::GpgKeyManager::DeleteSubkey(const GpgKey& key,
};
AutomatonActionHandler action_handler =
- [subkey_index](AutomatonHandelStruct& handler, AutomatonState state) {
+ [subkey_index, reason_code, reason_text_lines](
+ AutomatonHandelStruct& handler, AutomatonState state) {
switch (state) {
case AS_SELECT:
return QString("key %1").arg(subkey_index);
case AS_COMMAND:
- return QString("delkey");
+ return QString("revkey");
+ case AS_REASON_CODE:
+ return QString::number(reason_code);
+ case AS_REASON_TEXT:
+ return reason_text_lines->isEmpty()
+ ? QString("")
+ : QString(reason_text_lines->takeFirst().toUtf8());
case AS_REALLY_ULTIMATE:
- handler.SetSuccess(true);
return QString("Y");
case AS_QUIT:
return QString("quit");
diff --git a/src/core/function/gpg/GpgKeyManager.h b/src/core/function/gpg/GpgKeyManager.h
index 83a38d05..986e835f 100644
--- a/src/core/function/gpg/GpgKeyManager.h
+++ b/src/core/function/gpg/GpgKeyManager.h
@@ -101,6 +101,17 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyManager
*/
auto DeleteSubkey(const GpgKey& key, int subkey_index) -> bool;
+ /**
+ * @brief
+ *
+ * @param key
+ * @param subkey_index
+ * @return true
+ * @return false
+ */
+ auto RevokeSubkey(const GpgKey& key, int subkey_index, int reason_code,
+ const QString& reason_text) -> bool;
+
private:
static auto interactor_cb_fnc(void* handle, const char* status,
const char* args, int fd) -> gpgme_error_t;
@@ -111,6 +122,8 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyManager
AS_SELECT,
AS_COMMAND,
AS_VALUE,
+ AS_REASON_CODE,
+ AS_REASON_TEXT,
AS_REALLY_ULTIMATE,
AS_SAVE,
AS_ERROR,