feat: support uid revoke and uid delete operations
This commit is contained in:
parent
673a3a13fa
commit
af776283bd
157
src/core/function/gpg/GpgAutomatonHandler.cpp
Normal file
157
src/core/function/gpg/GpgAutomatonHandler.cpp
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (C) 2021-2024 Saturneric <eric@bktus.com>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* The initial version of the source code is inherited from
|
||||||
|
* the gpg4usb project, which is under GPL-3.0-or-later.
|
||||||
|
*
|
||||||
|
* All the source code of GpgFrontend was modified and released by
|
||||||
|
* Saturneric <eric@bktus.com> starting on May 12, 2021.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "GpgAutomatonHandler.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "core/model/GpgData.h"
|
||||||
|
#include "core/model/GpgKey.h"
|
||||||
|
#include "core/utils/GpgUtils.h"
|
||||||
|
|
||||||
|
namespace GpgFrontend {
|
||||||
|
|
||||||
|
GpgAutomatonHandler::GpgAutomatonHandler(int channel)
|
||||||
|
: SingletonFunctionObject<GpgAutomatonHandler>(channel) {}
|
||||||
|
|
||||||
|
auto GpgAutomatonHandler::interator_cb_func(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 GpgAutomatonHandler::DoInteract(
|
||||||
|
const GpgKey& key, AutomatonNextStateHandler next_state_handler,
|
||||||
|
AutomatonActionHandler action_handler) -> bool {
|
||||||
|
auto key_fpr = key.GetFingerprint();
|
||||||
|
AutomatonHandelStruct handel_struct(key_fpr);
|
||||||
|
handel_struct.SetHandler(std::move(next_state_handler),
|
||||||
|
std::move(action_handler));
|
||||||
|
|
||||||
|
GpgData data_out;
|
||||||
|
|
||||||
|
auto err =
|
||||||
|
gpgme_op_interact(ctx_.DefaultContext(), static_cast<gpgme_key_t>(key), 0,
|
||||||
|
GpgAutomatonHandler::interator_cb_func,
|
||||||
|
static_cast<void*>(&handel_struct), data_out);
|
||||||
|
return CheckGpgError(err) == GPG_ERR_NO_ERROR && handel_struct.Success();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GpgAutomatonHandler::AutomatonHandelStruct::NextState(
|
||||||
|
QString gpg_status, QString args) -> AutomatonState {
|
||||||
|
return next_state_handler_(current_state_, std::move(gpg_status),
|
||||||
|
std::move(args));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GpgAutomatonHandler::AutomatonHandelStruct::SetHandler(
|
||||||
|
AutomatonNextStateHandler next_state_handler,
|
||||||
|
AutomatonActionHandler action_handler) {
|
||||||
|
next_state_handler_ = std::move(next_state_handler);
|
||||||
|
action_handler_ = std::move(action_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GpgAutomatonHandler::AutomatonHandelStruct::CurrentStatus()
|
||||||
|
-> AutomatonState {
|
||||||
|
return current_state_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GpgAutomatonHandler::AutomatonHandelStruct::SetStatus(
|
||||||
|
AutomatonState next_state) {
|
||||||
|
current_state_ = next_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GpgAutomatonHandler::AutomatonHandelStruct::Action() -> Command {
|
||||||
|
return action_handler_(*this, current_state_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GpgAutomatonHandler::AutomatonHandelStruct::SetSuccess(bool success) {
|
||||||
|
success_ = success;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GpgAutomatonHandler::AutomatonHandelStruct::Success() const -> bool {
|
||||||
|
return success_;
|
||||||
|
}
|
||||||
|
auto GpgAutomatonHandler::AutomatonHandelStruct::KeyFpr() -> QString {
|
||||||
|
return key_fpr_;
|
||||||
|
}
|
||||||
|
|
||||||
|
GpgAutomatonHandler::AutomatonHandelStruct::AutomatonHandelStruct(
|
||||||
|
QString key_fpr)
|
||||||
|
: key_fpr_(std::move(key_fpr)) {}
|
||||||
|
} // namespace GpgFrontend
|
110
src/core/function/gpg/GpgAutomatonHandler.h
Normal file
110
src/core/function/gpg/GpgAutomatonHandler.h
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2021-2024 Saturneric <eric@bktus.com>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* The initial version of the source code is inherited from
|
||||||
|
* the gpg4usb project, which is under GPL-3.0-or-later.
|
||||||
|
*
|
||||||
|
* All the source code of GpgFrontend was modified and released by
|
||||||
|
* Saturneric <eric@bktus.com> starting on May 12, 2021.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/GpgFrontendCore.h"
|
||||||
|
#include "core/function/basic/GpgFunctionObject.h"
|
||||||
|
#include "core/function/gpg/GpgContext.h"
|
||||||
|
#include "core/typedef/GpgTypedef.h"
|
||||||
|
|
||||||
|
namespace GpgFrontend {
|
||||||
|
|
||||||
|
class GpgAutomatonHandler
|
||||||
|
: public SingletonFunctionObject<GpgAutomatonHandler> {
|
||||||
|
public:
|
||||||
|
using Command = QString;
|
||||||
|
using AutomatonState = enum {
|
||||||
|
AS_START,
|
||||||
|
AS_SELECT,
|
||||||
|
AS_COMMAND,
|
||||||
|
AS_VALUE,
|
||||||
|
AS_REASON_CODE,
|
||||||
|
AS_REASON_TEXT,
|
||||||
|
AS_REALLY_ULTIMATE,
|
||||||
|
AS_SAVE,
|
||||||
|
AS_ERROR,
|
||||||
|
AS_QUIT,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AutomatonHandelStruct;
|
||||||
|
|
||||||
|
using AutomatonActionHandler =
|
||||||
|
std::function<Command(AutomatonHandelStruct&, AutomatonState)>;
|
||||||
|
using AutomatonNextStateHandler =
|
||||||
|
std::function<AutomatonState(AutomatonState, QString, QString)>;
|
||||||
|
|
||||||
|
struct AutomatonHandelStruct {
|
||||||
|
explicit AutomatonHandelStruct(QString key_fpr);
|
||||||
|
void SetStatus(AutomatonState next_state);
|
||||||
|
auto CurrentStatus() -> AutomatonState;
|
||||||
|
void SetHandler(AutomatonNextStateHandler next_state_handler,
|
||||||
|
AutomatonActionHandler action_handler);
|
||||||
|
auto NextState(QString gpg_status, QString args) -> AutomatonState;
|
||||||
|
auto Action() -> Command;
|
||||||
|
void SetSuccess(bool success);
|
||||||
|
[[nodiscard]] auto Success() const -> bool;
|
||||||
|
auto KeyFpr() -> QString;
|
||||||
|
|
||||||
|
private:
|
||||||
|
AutomatonState current_state_ = AS_START;
|
||||||
|
AutomatonNextStateHandler next_state_handler_;
|
||||||
|
AutomatonActionHandler action_handler_;
|
||||||
|
bool success_ = false;
|
||||||
|
QString key_fpr_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Gpg Key Manager object
|
||||||
|
*
|
||||||
|
* @param channel
|
||||||
|
*/
|
||||||
|
explicit GpgAutomatonHandler(
|
||||||
|
int channel = SingletonFunctionObject::GetDefaultChannel());
|
||||||
|
|
||||||
|
auto DoInteract(const GpgKey& key,
|
||||||
|
AutomatonNextStateHandler next_state_handler,
|
||||||
|
AutomatonActionHandler action_handler) -> bool;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static auto interator_cb_func(void* handle, const char* status,
|
||||||
|
const char* args, int fd) -> gpgme_error_t;
|
||||||
|
|
||||||
|
GpgContext& ctx_ =
|
||||||
|
GpgContext::GetInstance(SingletonFunctionObject::GetChannel()); ///<
|
||||||
|
};
|
||||||
|
|
||||||
|
using AutomatonNextStateHandler =
|
||||||
|
GpgAutomatonHandler::AutomatonNextStateHandler;
|
||||||
|
using AutomatonState = GpgAutomatonHandler::AutomatonState;
|
||||||
|
using AutomatonActionHandler = GpgAutomatonHandler::AutomatonActionHandler;
|
||||||
|
using AutomatonHandelStruct = GpgAutomatonHandler::AutomatonHandelStruct;
|
||||||
|
|
||||||
|
} // namespace GpgFrontend
|
@ -29,74 +29,19 @@
|
|||||||
#include "GpgKeyManager.h"
|
#include "GpgKeyManager.h"
|
||||||
|
|
||||||
#include "core/GpgModel.h"
|
#include "core/GpgModel.h"
|
||||||
|
#include "core/function/gpg/GpgAutomatonHandler.h"
|
||||||
#include "core/function/gpg/GpgBasicOperator.h"
|
#include "core/function/gpg/GpgBasicOperator.h"
|
||||||
#include "core/function/gpg/GpgKeyGetter.h"
|
#include "core/function/gpg/GpgKeyGetter.h"
|
||||||
#include "core/utils/GpgUtils.h"
|
#include "core/utils/GpgUtils.h"
|
||||||
|
|
||||||
GpgFrontend::GpgKeyManager::GpgKeyManager(int channel)
|
namespace GpgFrontend {
|
||||||
|
|
||||||
|
GpgKeyManager::GpgKeyManager(int channel)
|
||||||
: SingletonFunctionObject<GpgKeyManager>(channel) {}
|
: SingletonFunctionObject<GpgKeyManager>(channel) {}
|
||||||
|
|
||||||
auto GpgFrontend::GpgKeyManager::interactor_cb_fnc(void* handle,
|
auto GpgKeyManager::SignKey(const GpgKey& target, KeyArgsList& keys,
|
||||||
const char* status,
|
const QString& uid,
|
||||||
const char* args,
|
const std::unique_ptr<QDateTime>& expires) -> bool {
|
||||||
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 {
|
|
||||||
GpgBasicOperator::GetInstance(GetChannel()).SetSigners(keys, true);
|
GpgBasicOperator::GetInstance(GetChannel()).SetSigners(keys, true);
|
||||||
|
|
||||||
unsigned int flags = 0;
|
unsigned int flags = 0;
|
||||||
@ -115,9 +60,8 @@ auto GpgFrontend::GpgKeyManager::SignKey(
|
|||||||
return CheckGpgError(err) == GPG_ERR_NO_ERROR;
|
return CheckGpgError(err) == GPG_ERR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto GpgFrontend::GpgKeyManager::RevSign(
|
auto GpgKeyManager::RevSign(const GpgKey& key,
|
||||||
const GpgFrontend::GpgKey& key,
|
const SignIdArgsListPtr& signature_id) -> bool {
|
||||||
const GpgFrontend::SignIdArgsListPtr& signature_id) -> bool {
|
|
||||||
auto& key_getter = GpgKeyGetter::GetInstance(GetChannel());
|
auto& key_getter = GpgKeyGetter::GetInstance(GetChannel());
|
||||||
|
|
||||||
for (const auto& sign_id : *signature_id) {
|
for (const auto& sign_id : *signature_id) {
|
||||||
@ -132,8 +76,8 @@ auto GpgFrontend::GpgKeyManager::RevSign(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto GpgFrontend::GpgKeyManager::SetExpire(
|
auto GpgKeyManager::SetExpire(const GpgKey& key,
|
||||||
const GpgFrontend::GpgKey& key, std::unique_ptr<GpgSubKey>& subkey,
|
std::unique_ptr<GpgSubKey>& subkey,
|
||||||
std::unique_ptr<QDateTime>& expires) -> bool {
|
std::unique_ptr<QDateTime>& expires) -> bool {
|
||||||
unsigned long expires_time = 0;
|
unsigned long expires_time = 0;
|
||||||
|
|
||||||
@ -150,73 +94,73 @@ auto GpgFrontend::GpgKeyManager::SetExpire(
|
|||||||
return CheckGpgError(err) == GPG_ERR_NO_ERROR;
|
return CheckGpgError(err) == GPG_ERR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto GpgFrontend::GpgKeyManager::SetOwnerTrustLevel(const GpgKey& key,
|
auto GpgKeyManager::SetOwnerTrustLevel(const GpgKey& key,
|
||||||
int trust_level) -> bool {
|
int trust_level) -> bool {
|
||||||
if (trust_level < 1 || trust_level > 5) {
|
if (trust_level < 1 || trust_level > 5) {
|
||||||
FLOG_W("illegal owner trust level: %d", trust_level);
|
FLOG_W("illegal owner trust level: %d", trust_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
AutomatonNextStateHandler next_state_handler =
|
GpgAutomatonHandler::AutomatonNextStateHandler next_state_handler =
|
||||||
[](AutomatonState state, QString status, QString args) {
|
[](AutomatonState state, QString status, QString args) {
|
||||||
auto tokens = args.split(' ');
|
auto tokens = args.split(' ');
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case AS_START:
|
case GpgAutomatonHandler::AS_START:
|
||||||
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
||||||
return AS_COMMAND;
|
return GpgAutomatonHandler::AS_COMMAND;
|
||||||
}
|
}
|
||||||
return AS_ERROR;
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
case AS_COMMAND:
|
case GpgAutomatonHandler::AS_COMMAND:
|
||||||
if (status == "GET_LINE" && args == "edit_ownertrust.value") {
|
if (status == "GET_LINE" && args == "edit_ownertrust.value") {
|
||||||
return AS_VALUE;
|
return GpgAutomatonHandler::AS_VALUE;
|
||||||
}
|
}
|
||||||
return AS_ERROR;
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
case AS_VALUE:
|
case GpgAutomatonHandler::AS_VALUE:
|
||||||
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
||||||
return AS_QUIT;
|
return GpgAutomatonHandler::AS_QUIT;
|
||||||
} else if (status == "GET_BOOL" &&
|
} else if (status == "GET_BOOL" &&
|
||||||
args == "edit_ownertrust.set_ultimate.okay") {
|
args == "edit_ownertrust.set_ultimate.okay") {
|
||||||
return AS_REALLY_ULTIMATE;
|
return GpgAutomatonHandler::AS_REALLY_ULTIMATE;
|
||||||
}
|
}
|
||||||
return AS_ERROR;
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
case AS_REALLY_ULTIMATE:
|
case GpgAutomatonHandler::AS_REALLY_ULTIMATE:
|
||||||
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
||||||
return AS_QUIT;
|
return GpgAutomatonHandler::AS_QUIT;
|
||||||
}
|
}
|
||||||
return AS_ERROR;
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
case AS_QUIT:
|
case GpgAutomatonHandler::AS_QUIT:
|
||||||
if (status == "GET_BOOL" && args == "keyedit.save.okay") {
|
if (status == "GET_BOOL" && args == "keyedit.save.okay") {
|
||||||
return AS_SAVE;
|
return GpgAutomatonHandler::AS_SAVE;
|
||||||
}
|
}
|
||||||
return AS_ERROR;
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
case AS_ERROR:
|
case GpgAutomatonHandler::AS_ERROR:
|
||||||
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
||||||
return AS_QUIT;
|
return GpgAutomatonHandler::AS_QUIT;
|
||||||
}
|
}
|
||||||
return AS_ERROR;
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
default:
|
default:
|
||||||
return AS_ERROR;
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
AutomatonActionHandler action_handler =
|
AutomatonActionHandler action_handler =
|
||||||
[trust_level](AutomatonHandelStruct& handler, AutomatonState state) {
|
[trust_level](AutomatonHandelStruct& handler, AutomatonState state) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case AS_COMMAND:
|
case GpgAutomatonHandler::AS_COMMAND:
|
||||||
return QString("trust");
|
return QString("trust");
|
||||||
case AS_VALUE:
|
case GpgAutomatonHandler::AS_VALUE:
|
||||||
handler.SetSuccess(true);
|
handler.SetSuccess(true);
|
||||||
return QString::number(trust_level);
|
return QString::number(trust_level);
|
||||||
case AS_REALLY_ULTIMATE:
|
case GpgAutomatonHandler::AS_REALLY_ULTIMATE:
|
||||||
handler.SetSuccess(true);
|
handler.SetSuccess(true);
|
||||||
return QString("Y");
|
return QString("Y");
|
||||||
case AS_QUIT:
|
case GpgAutomatonHandler::AS_QUIT:
|
||||||
return QString("quit");
|
return QString("quit");
|
||||||
case AS_SAVE:
|
case GpgAutomatonHandler::AS_SAVE:
|
||||||
handler.SetSuccess(true);
|
handler.SetSuccess(true);
|
||||||
return QString("Y");
|
return QString("Y");
|
||||||
case AS_START:
|
case GpgAutomatonHandler::AS_START:
|
||||||
case AS_ERROR:
|
case GpgAutomatonHandler::AS_ERROR:
|
||||||
return QString("");
|
return QString("");
|
||||||
default:
|
default:
|
||||||
return QString("");
|
return QString("");
|
||||||
@ -224,23 +168,14 @@ auto GpgFrontend::GpgKeyManager::SetOwnerTrustLevel(const GpgKey& key,
|
|||||||
return QString("");
|
return QString("");
|
||||||
};
|
};
|
||||||
|
|
||||||
auto key_fpr = key.GetFingerprint();
|
return GpgAutomatonHandler::GetInstance(GetChannel())
|
||||||
AutomatonHandelStruct handel_struct(key_fpr);
|
.DoInteract(key, next_state_handler, action_handler);
|
||||||
handel_struct.SetHandler(next_state_handler, action_handler);
|
|
||||||
|
|
||||||
GpgData data_out;
|
|
||||||
|
|
||||||
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,
|
auto GpgKeyManager::DeleteSubkey(const GpgKey& key, int subkey_index) -> bool {
|
||||||
int subkey_index) -> bool {
|
|
||||||
if (subkey_index < 0 || subkey_index >= key.GetSubKeys()->size()) {
|
if (subkey_index < 0 || subkey_index >= key.GetSubKeys()->size()) {
|
||||||
LOG_W() << "illegal subkey index: " << subkey_index;
|
LOG_W() << "illegal subkey index: " << subkey_index;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
AutomatonNextStateHandler next_state_handler =
|
AutomatonNextStateHandler next_state_handler =
|
||||||
@ -248,61 +183,61 @@ auto GpgFrontend::GpgKeyManager::DeleteSubkey(const GpgKey& key,
|
|||||||
auto tokens = args.split(' ');
|
auto tokens = args.split(' ');
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case AS_START:
|
case GpgAutomatonHandler::AS_START:
|
||||||
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
||||||
return AS_SELECT;
|
return GpgAutomatonHandler::AS_SELECT;
|
||||||
}
|
}
|
||||||
return AS_ERROR;
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
case AS_SELECT:
|
case GpgAutomatonHandler::AS_SELECT:
|
||||||
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
||||||
return AS_COMMAND;
|
return GpgAutomatonHandler::AS_COMMAND;
|
||||||
}
|
}
|
||||||
return AS_ERROR;
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
case AS_COMMAND:
|
case GpgAutomatonHandler::AS_COMMAND:
|
||||||
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
||||||
return AS_QUIT;
|
return GpgAutomatonHandler::AS_QUIT;
|
||||||
} else if (status == "GET_BOOL" &&
|
} else if (status == "GET_BOOL" &&
|
||||||
args == "keyedit.remove.subkey.okay") {
|
args == "keyedit.remove.subkey.okay") {
|
||||||
return AS_REALLY_ULTIMATE;
|
return GpgAutomatonHandler::AS_REALLY_ULTIMATE;
|
||||||
}
|
}
|
||||||
return AS_ERROR;
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
case AS_REALLY_ULTIMATE:
|
case GpgAutomatonHandler::AS_REALLY_ULTIMATE:
|
||||||
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
||||||
return AS_QUIT;
|
return GpgAutomatonHandler::AS_QUIT;
|
||||||
}
|
}
|
||||||
return AS_ERROR;
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
case AS_QUIT:
|
case GpgAutomatonHandler::AS_QUIT:
|
||||||
if (status == "GET_BOOL" && args == "keyedit.save.okay") {
|
if (status == "GET_BOOL" && args == "keyedit.save.okay") {
|
||||||
return AS_SAVE;
|
return GpgAutomatonHandler::AS_SAVE;
|
||||||
}
|
}
|
||||||
return AS_ERROR;
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
case AS_ERROR:
|
case GpgAutomatonHandler::AS_ERROR:
|
||||||
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
||||||
return AS_QUIT;
|
return GpgAutomatonHandler::AS_QUIT;
|
||||||
}
|
}
|
||||||
return AS_ERROR;
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
default:
|
default:
|
||||||
return AS_ERROR;
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
AutomatonActionHandler action_handler =
|
AutomatonActionHandler action_handler =
|
||||||
[subkey_index](AutomatonHandelStruct& handler, AutomatonState state) {
|
[subkey_index](AutomatonHandelStruct& handler, AutomatonState state) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case AS_SELECT:
|
case GpgAutomatonHandler::AS_SELECT:
|
||||||
return QString("key %1").arg(subkey_index);
|
return QString("key %1").arg(subkey_index);
|
||||||
case AS_COMMAND:
|
case GpgAutomatonHandler::AS_COMMAND:
|
||||||
return QString("delkey");
|
return QString("delkey");
|
||||||
case AS_REALLY_ULTIMATE:
|
case GpgAutomatonHandler::AS_REALLY_ULTIMATE:
|
||||||
handler.SetSuccess(true);
|
handler.SetSuccess(true);
|
||||||
return QString("Y");
|
return QString("Y");
|
||||||
case AS_QUIT:
|
case GpgAutomatonHandler::AS_QUIT:
|
||||||
return QString("quit");
|
return QString("quit");
|
||||||
case AS_SAVE:
|
case GpgAutomatonHandler::AS_SAVE:
|
||||||
handler.SetSuccess(true);
|
handler.SetSuccess(true);
|
||||||
return QString("Y");
|
return QString("Y");
|
||||||
case AS_START:
|
case GpgAutomatonHandler::AS_START:
|
||||||
case AS_ERROR:
|
case GpgAutomatonHandler::AS_ERROR:
|
||||||
return QString("");
|
return QString("");
|
||||||
default:
|
default:
|
||||||
return QString("");
|
return QString("");
|
||||||
@ -316,28 +251,29 @@ auto GpgFrontend::GpgKeyManager::DeleteSubkey(const GpgKey& key,
|
|||||||
|
|
||||||
GpgData data_out;
|
GpgData data_out;
|
||||||
|
|
||||||
auto err =
|
return GpgAutomatonHandler::GetInstance(GetChannel())
|
||||||
gpgme_op_interact(ctx_.DefaultContext(), static_cast<gpgme_key_t>(key), 0,
|
.DoInteract(key, next_state_handler, action_handler);
|
||||||
GpgKeyManager::interactor_cb_fnc,
|
|
||||||
static_cast<void*>(&handel_struct), data_out);
|
|
||||||
return CheckGpgError(err) == GPG_ERR_NO_ERROR && handel_struct.Success();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto GpgFrontend::GpgKeyManager::RevokeSubkey(
|
auto GpgKeyManager::RevokeSubkey(const GpgKey& key, int subkey_index,
|
||||||
const GpgKey& key, int subkey_index, int reason_code,
|
int reason_code,
|
||||||
const QString& reason_text) -> bool {
|
const QString& reason_text) -> bool {
|
||||||
if (subkey_index < 0 || subkey_index >= key.GetSubKeys()->size()) {
|
if (subkey_index < 0 || subkey_index >= key.GetSubKeys()->size()) {
|
||||||
LOG_W() << "illegal subkey index: " << subkey_index;
|
LOG_W() << "illegal subkey index: " << subkey_index;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reason_code < 0 || reason_code > 3) {
|
||||||
|
LOG_W() << "illegal reason code: " << reason_code;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// dealing with reason text
|
// dealing with reason text
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 4)
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 4)
|
||||||
auto reason_text_lines =
|
auto reason_text_lines = SecureCreateSharedObject<QList<QString>>(
|
||||||
GpgFrontend::SecureCreateSharedObject<QList<QString>>(
|
|
||||||
reason_text.split('\n', Qt::SkipEmptyParts).toVector());
|
reason_text.split('\n', Qt::SkipEmptyParts).toVector());
|
||||||
#else
|
#else
|
||||||
auto reason_text_lines =
|
auto reason_text_lines = SecureCreateSharedObject<QVector<QString>>(
|
||||||
GpgFrontend::SecureCreateSharedObject<QVector<QString>>(
|
|
||||||
reason_text.split('\n', Qt::SkipEmptyParts).toVector());
|
reason_text.split('\n', Qt::SkipEmptyParts).toVector());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -346,63 +282,63 @@ auto GpgFrontend::GpgKeyManager::RevokeSubkey(
|
|||||||
auto tokens = args.split(' ');
|
auto tokens = args.split(' ');
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case AS_START:
|
case GpgAutomatonHandler::AS_START:
|
||||||
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
||||||
return AS_SELECT;
|
return GpgAutomatonHandler::AS_SELECT;
|
||||||
}
|
}
|
||||||
return AS_ERROR;
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
case AS_SELECT:
|
case GpgAutomatonHandler::AS_SELECT:
|
||||||
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
||||||
return AS_COMMAND;
|
return GpgAutomatonHandler::AS_COMMAND;
|
||||||
}
|
}
|
||||||
return AS_ERROR;
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
case AS_COMMAND:
|
case GpgAutomatonHandler::AS_COMMAND:
|
||||||
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
||||||
return AS_QUIT;
|
return GpgAutomatonHandler::AS_QUIT;
|
||||||
} else if (status == "GET_BOOL" &&
|
} else if (status == "GET_BOOL" &&
|
||||||
args == "keyedit.revoke.subkey.okay") {
|
args == "keyedit.revoke.subkey.okay") {
|
||||||
return AS_REALLY_ULTIMATE;
|
return GpgAutomatonHandler::AS_REALLY_ULTIMATE;
|
||||||
}
|
}
|
||||||
return AS_ERROR;
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
case AS_REASON_CODE:
|
case GpgAutomatonHandler::AS_REASON_CODE:
|
||||||
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
||||||
return AS_QUIT;
|
return GpgAutomatonHandler::AS_QUIT;
|
||||||
} else if (status == "GET_LINE" &&
|
} else if (status == "GET_LINE" &&
|
||||||
args == "ask_revocation_reason.text") {
|
args == "ask_revocation_reason.text") {
|
||||||
return AS_REASON_TEXT;
|
return GpgAutomatonHandler::AS_REASON_TEXT;
|
||||||
}
|
}
|
||||||
return AS_ERROR;
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
case AS_REASON_TEXT:
|
case GpgAutomatonHandler::AS_REASON_TEXT:
|
||||||
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
||||||
return AS_QUIT;
|
return GpgAutomatonHandler::AS_QUIT;
|
||||||
} else if (status == "GET_LINE" &&
|
} else if (status == "GET_LINE" &&
|
||||||
args == "ask_revocation_reason.text") {
|
args == "ask_revocation_reason.text") {
|
||||||
return AS_REASON_TEXT;
|
return GpgAutomatonHandler::AS_REASON_TEXT;
|
||||||
} else if (status == "GET_BOOL" &&
|
} else if (status == "GET_BOOL" &&
|
||||||
args == "ask_revocation_reason.okay") {
|
args == "ask_revocation_reason.okay") {
|
||||||
return AS_REALLY_ULTIMATE;
|
return GpgAutomatonHandler::AS_REALLY_ULTIMATE;
|
||||||
}
|
}
|
||||||
return AS_ERROR;
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
case AS_REALLY_ULTIMATE:
|
case GpgAutomatonHandler::AS_REALLY_ULTIMATE:
|
||||||
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
||||||
return AS_QUIT;
|
return GpgAutomatonHandler::AS_QUIT;
|
||||||
} else if (status == "GET_LINE" &&
|
} else if (status == "GET_LINE" &&
|
||||||
args == "ask_revocation_reason.code") {
|
args == "ask_revocation_reason.code") {
|
||||||
return AS_REASON_CODE;
|
return GpgAutomatonHandler::AS_REASON_CODE;
|
||||||
}
|
}
|
||||||
return AS_ERROR;
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
case AS_QUIT:
|
case GpgAutomatonHandler::AS_QUIT:
|
||||||
if (status == "GET_BOOL" && args == "keyedit.save.okay") {
|
if (status == "GET_BOOL" && args == "keyedit.save.okay") {
|
||||||
return AS_SAVE;
|
return GpgAutomatonHandler::AS_SAVE;
|
||||||
}
|
}
|
||||||
return AS_ERROR;
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
case AS_ERROR:
|
case GpgAutomatonHandler::AS_ERROR:
|
||||||
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
||||||
return AS_QUIT;
|
return GpgAutomatonHandler::AS_QUIT;
|
||||||
}
|
}
|
||||||
return AS_ERROR;
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
default:
|
default:
|
||||||
return AS_ERROR;
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -410,25 +346,25 @@ auto GpgFrontend::GpgKeyManager::RevokeSubkey(
|
|||||||
[subkey_index, reason_code, reason_text_lines](
|
[subkey_index, reason_code, reason_text_lines](
|
||||||
AutomatonHandelStruct& handler, AutomatonState state) {
|
AutomatonHandelStruct& handler, AutomatonState state) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case AS_SELECT:
|
case GpgAutomatonHandler::AS_SELECT:
|
||||||
return QString("key %1").arg(subkey_index);
|
return QString("key %1").arg(subkey_index);
|
||||||
case AS_COMMAND:
|
case GpgAutomatonHandler::AS_COMMAND:
|
||||||
return QString("revkey");
|
return QString("revkey");
|
||||||
case AS_REASON_CODE:
|
case GpgAutomatonHandler::AS_REASON_CODE:
|
||||||
return QString::number(reason_code);
|
return QString::number(reason_code);
|
||||||
case AS_REASON_TEXT:
|
case GpgAutomatonHandler::AS_REASON_TEXT:
|
||||||
return reason_text_lines->isEmpty()
|
return reason_text_lines->isEmpty()
|
||||||
? QString("")
|
? QString("")
|
||||||
: QString(reason_text_lines->takeFirst().toUtf8());
|
: QString(reason_text_lines->takeFirst().toUtf8());
|
||||||
case AS_REALLY_ULTIMATE:
|
case GpgAutomatonHandler::AS_REALLY_ULTIMATE:
|
||||||
return QString("Y");
|
return QString("Y");
|
||||||
case AS_QUIT:
|
case GpgAutomatonHandler::AS_QUIT:
|
||||||
return QString("quit");
|
return QString("quit");
|
||||||
case AS_SAVE:
|
case GpgAutomatonHandler::AS_SAVE:
|
||||||
handler.SetSuccess(true);
|
handler.SetSuccess(true);
|
||||||
return QString("Y");
|
return QString("Y");
|
||||||
case AS_START:
|
case GpgAutomatonHandler::AS_START:
|
||||||
case AS_ERROR:
|
case GpgAutomatonHandler::AS_ERROR:
|
||||||
return QString("");
|
return QString("");
|
||||||
default:
|
default:
|
||||||
return QString("");
|
return QString("");
|
||||||
@ -442,9 +378,8 @@ auto GpgFrontend::GpgKeyManager::RevokeSubkey(
|
|||||||
|
|
||||||
GpgData data_out;
|
GpgData data_out;
|
||||||
|
|
||||||
auto err =
|
return GpgAutomatonHandler::GetInstance(GetChannel())
|
||||||
gpgme_op_interact(ctx_.DefaultContext(), static_cast<gpgme_key_t>(key), 0,
|
.DoInteract(key, next_state_handler, action_handler);
|
||||||
GpgKeyManager::interactor_cb_fnc,
|
|
||||||
static_cast<void*>(&handel_struct), data_out);
|
|
||||||
return CheckGpgError(err) == GPG_ERR_NO_ERROR && handel_struct.Success();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace GpgFrontend
|
@ -28,8 +28,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
#include "core/function/basic/GpgFunctionObject.h"
|
#include "core/function/basic/GpgFunctionObject.h"
|
||||||
#include "core/function/gpg/GpgContext.h"
|
#include "core/function/gpg/GpgContext.h"
|
||||||
#include "core/typedef/GpgTypedef.h"
|
#include "core/typedef/GpgTypedef.h"
|
||||||
@ -113,61 +111,6 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyManager
|
|||||||
const QString& reason_text) -> bool;
|
const QString& reason_text) -> bool;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static auto interactor_cb_fnc(void* handle, const char* status,
|
|
||||||
const char* args, int fd) -> gpgme_error_t;
|
|
||||||
|
|
||||||
using Command = QString;
|
|
||||||
using AutomatonState = enum {
|
|
||||||
AS_START,
|
|
||||||
AS_SELECT,
|
|
||||||
AS_COMMAND,
|
|
||||||
AS_VALUE,
|
|
||||||
AS_REASON_CODE,
|
|
||||||
AS_REASON_TEXT,
|
|
||||||
AS_REALLY_ULTIMATE,
|
|
||||||
AS_SAVE,
|
|
||||||
AS_ERROR,
|
|
||||||
AS_QUIT,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AutomatonHandelStruct;
|
|
||||||
|
|
||||||
using AutomatonActionHandler =
|
|
||||||
std::function<Command(AutomatonHandelStruct&, AutomatonState)>;
|
|
||||||
using AutomatonNextStateHandler =
|
|
||||||
std::function<AutomatonState(AutomatonState, QString, QString)>;
|
|
||||||
|
|
||||||
struct AutomatonHandelStruct {
|
|
||||||
void SetStatus(AutomatonState next_state) { current_state_ = next_state; }
|
|
||||||
auto CurrentStatus() -> AutomatonState { return current_state_; }
|
|
||||||
void SetHandler(AutomatonNextStateHandler next_state_handler,
|
|
||||||
AutomatonActionHandler action_handler) {
|
|
||||||
next_state_handler_ = std::move(next_state_handler);
|
|
||||||
action_handler_ = std::move(action_handler);
|
|
||||||
}
|
|
||||||
auto NextState(QString gpg_status, QString args) -> AutomatonState {
|
|
||||||
return next_state_handler_(current_state_, std::move(gpg_status),
|
|
||||||
std::move(args));
|
|
||||||
}
|
|
||||||
auto Action() -> Command { return action_handler_(*this, current_state_); }
|
|
||||||
|
|
||||||
void SetSuccess(bool success) { success_ = success; }
|
|
||||||
|
|
||||||
[[nodiscard]] auto Success() const -> bool { return success_; }
|
|
||||||
|
|
||||||
auto KeyFpr() -> QString { return key_fpr_; }
|
|
||||||
|
|
||||||
explicit AutomatonHandelStruct(QString key_fpr)
|
|
||||||
: key_fpr_(std::move(key_fpr)) {}
|
|
||||||
|
|
||||||
private:
|
|
||||||
AutomatonState current_state_ = AS_START;
|
|
||||||
AutomatonNextStateHandler next_state_handler_;
|
|
||||||
AutomatonActionHandler action_handler_;
|
|
||||||
bool success_ = false;
|
|
||||||
QString key_fpr_;
|
|
||||||
};
|
|
||||||
|
|
||||||
GpgContext& ctx_ =
|
GpgContext& ctx_ =
|
||||||
GpgContext::GetInstance(SingletonFunctionObject::GetChannel()); ///<
|
GpgContext::GetInstance(SingletonFunctionObject::GetChannel()); ///<
|
||||||
};
|
};
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include "GpgUIDOperator.h"
|
#include "GpgUIDOperator.h"
|
||||||
|
|
||||||
#include "core/GpgModel.h"
|
#include "core/GpgModel.h"
|
||||||
|
#include "core/function/gpg/GpgAutomatonHandler.h"
|
||||||
#include "core/utils/GpgUtils.h"
|
#include "core/utils/GpgUtils.h"
|
||||||
|
|
||||||
namespace GpgFrontend {
|
namespace GpgFrontend {
|
||||||
@ -42,12 +43,6 @@ auto GpgUIDOperator::AddUID(const GpgKey& key, const QString& uid) -> bool {
|
|||||||
return CheckGpgError(err) == GPG_ERR_NO_ERROR;
|
return CheckGpgError(err) == GPG_ERR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto GpgUIDOperator::RevUID(const GpgKey& key, const QString& uid) -> bool {
|
|
||||||
auto err = CheckGpgError(gpgme_op_revuid(
|
|
||||||
ctx_.DefaultContext(), static_cast<gpgme_key_t>(key), uid.toUtf8(), 0));
|
|
||||||
return CheckGpgError(err) == GPG_ERR_NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto GpgUIDOperator::SetPrimaryUID(const GpgKey& key,
|
auto GpgUIDOperator::SetPrimaryUID(const GpgKey& key,
|
||||||
const QString& uid) -> bool {
|
const QString& uid) -> bool {
|
||||||
auto err = CheckGpgError(gpgme_op_set_uid_flag(
|
auto err = CheckGpgError(gpgme_op_set_uid_flag(
|
||||||
@ -55,6 +50,7 @@ auto GpgUIDOperator::SetPrimaryUID(const GpgKey& key,
|
|||||||
"primary", nullptr));
|
"primary", nullptr));
|
||||||
return CheckGpgError(err) == GPG_ERR_NO_ERROR;
|
return CheckGpgError(err) == GPG_ERR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto GpgUIDOperator::AddUID(const GpgKey& key, const QString& name,
|
auto GpgUIDOperator::AddUID(const GpgKey& key, const QString& name,
|
||||||
const QString& comment,
|
const QString& comment,
|
||||||
const QString& email) -> bool {
|
const QString& email) -> bool {
|
||||||
@ -62,4 +58,216 @@ auto GpgUIDOperator::AddUID(const GpgKey& key, const QString& name,
|
|||||||
return AddUID(key, QString("%1(%2)<%3>").arg(name).arg(comment).arg(email));
|
return AddUID(key, QString("%1(%2)<%3>").arg(name).arg(comment).arg(email));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto GpgUIDOperator::DeleteUID(const GpgKey& key, int uid_index) -> bool {
|
||||||
|
if (uid_index < 2 || uid_index > key.GetUIDs()->size()) {
|
||||||
|
LOG_W() << "illegal uid_index index: " << uid_index;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AutomatonNextStateHandler next_state_handler = [](AutomatonState state,
|
||||||
|
QString status,
|
||||||
|
QString args) {
|
||||||
|
auto tokens = args.split(' ');
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case GpgAutomatonHandler::AS_START:
|
||||||
|
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
||||||
|
return GpgAutomatonHandler::AS_SELECT;
|
||||||
|
}
|
||||||
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
|
case GpgAutomatonHandler::AS_SELECT:
|
||||||
|
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
||||||
|
return GpgAutomatonHandler::AS_COMMAND;
|
||||||
|
}
|
||||||
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
|
case GpgAutomatonHandler::AS_COMMAND:
|
||||||
|
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
||||||
|
return GpgAutomatonHandler::AS_QUIT;
|
||||||
|
} else if (status == "GET_BOOL" && args == "keyedit.remove.uid.okay") {
|
||||||
|
return GpgAutomatonHandler::AS_REALLY_ULTIMATE;
|
||||||
|
}
|
||||||
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
|
case GpgAutomatonHandler::AS_REALLY_ULTIMATE:
|
||||||
|
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
||||||
|
return GpgAutomatonHandler::AS_QUIT;
|
||||||
|
}
|
||||||
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
|
case GpgAutomatonHandler::AS_QUIT:
|
||||||
|
if (status == "GET_BOOL" && args == "keyedit.save.okay") {
|
||||||
|
return GpgAutomatonHandler::AS_SAVE;
|
||||||
|
}
|
||||||
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
|
case GpgAutomatonHandler::AS_ERROR:
|
||||||
|
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
||||||
|
return GpgAutomatonHandler::AS_QUIT;
|
||||||
|
}
|
||||||
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
|
default:
|
||||||
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
AutomatonActionHandler action_handler =
|
||||||
|
[uid_index](AutomatonHandelStruct& handler, AutomatonState state) {
|
||||||
|
switch (state) {
|
||||||
|
case GpgAutomatonHandler::AS_SELECT:
|
||||||
|
return QString("uid %1").arg(uid_index);
|
||||||
|
case GpgAutomatonHandler::AS_COMMAND:
|
||||||
|
return QString("deluid");
|
||||||
|
case GpgAutomatonHandler::AS_REALLY_ULTIMATE:
|
||||||
|
handler.SetSuccess(true);
|
||||||
|
return QString("Y");
|
||||||
|
case GpgAutomatonHandler::AS_QUIT:
|
||||||
|
return QString("quit");
|
||||||
|
case GpgAutomatonHandler::AS_SAVE:
|
||||||
|
handler.SetSuccess(true);
|
||||||
|
return QString("Y");
|
||||||
|
case GpgAutomatonHandler::AS_START:
|
||||||
|
case GpgAutomatonHandler::AS_ERROR:
|
||||||
|
return QString("");
|
||||||
|
default:
|
||||||
|
return QString("");
|
||||||
|
}
|
||||||
|
return QString("");
|
||||||
|
};
|
||||||
|
|
||||||
|
auto key_fpr = key.GetFingerprint();
|
||||||
|
AutomatonHandelStruct handel_struct(key_fpr);
|
||||||
|
handel_struct.SetHandler(next_state_handler, action_handler);
|
||||||
|
|
||||||
|
GpgData data_out;
|
||||||
|
|
||||||
|
return GpgAutomatonHandler::GetInstance(GetChannel())
|
||||||
|
.DoInteract(key, next_state_handler, action_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GpgUIDOperator::RevokeUID(const GpgKey& key, int uid_index,
|
||||||
|
int reason_code,
|
||||||
|
const QString& reason_text) -> bool {
|
||||||
|
if (uid_index < 2 || uid_index > key.GetUIDs()->size()) {
|
||||||
|
LOG_W() << "illegal uid index: " << uid_index;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reason_code != 0 && reason_code != 4) {
|
||||||
|
LOG_W() << "illegal reason code: " << reason_code;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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(' ');
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case GpgAutomatonHandler::AS_START:
|
||||||
|
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
||||||
|
return GpgAutomatonHandler::AS_SELECT;
|
||||||
|
}
|
||||||
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
|
case GpgAutomatonHandler::AS_SELECT:
|
||||||
|
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
||||||
|
return GpgAutomatonHandler::AS_COMMAND;
|
||||||
|
}
|
||||||
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
|
case GpgAutomatonHandler::AS_COMMAND:
|
||||||
|
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
||||||
|
return GpgAutomatonHandler::AS_QUIT;
|
||||||
|
} else if (status == "GET_BOOL" && args == "keyedit.revoke.uid.okay") {
|
||||||
|
return GpgAutomatonHandler::AS_REALLY_ULTIMATE;
|
||||||
|
}
|
||||||
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
|
case GpgAutomatonHandler::AS_REASON_CODE:
|
||||||
|
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
||||||
|
return GpgAutomatonHandler::AS_QUIT;
|
||||||
|
} else if (status == "GET_LINE" &&
|
||||||
|
args == "ask_revocation_reason.text") {
|
||||||
|
return GpgAutomatonHandler::AS_REASON_TEXT;
|
||||||
|
}
|
||||||
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
|
case GpgAutomatonHandler::AS_REASON_TEXT:
|
||||||
|
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
||||||
|
return GpgAutomatonHandler::AS_QUIT;
|
||||||
|
} else if (status == "GET_LINE" &&
|
||||||
|
args == "ask_revocation_reason.text") {
|
||||||
|
return GpgAutomatonHandler::AS_REASON_TEXT;
|
||||||
|
} else if (status == "GET_BOOL" &&
|
||||||
|
args == "ask_revocation_reason.okay") {
|
||||||
|
return GpgAutomatonHandler::AS_REALLY_ULTIMATE;
|
||||||
|
}
|
||||||
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
|
case GpgAutomatonHandler::AS_REALLY_ULTIMATE:
|
||||||
|
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
||||||
|
return GpgAutomatonHandler::AS_QUIT;
|
||||||
|
} else if (status == "GET_LINE" &&
|
||||||
|
args == "ask_revocation_reason.code") {
|
||||||
|
return GpgAutomatonHandler::AS_REASON_CODE;
|
||||||
|
}
|
||||||
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
|
case GpgAutomatonHandler::AS_QUIT:
|
||||||
|
if (status == "GET_BOOL" && args == "keyedit.save.okay") {
|
||||||
|
return GpgAutomatonHandler::AS_SAVE;
|
||||||
|
}
|
||||||
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
|
case GpgAutomatonHandler::AS_ERROR:
|
||||||
|
if (status == "GET_LINE" && args == "keyedit.prompt") {
|
||||||
|
return GpgAutomatonHandler::AS_QUIT;
|
||||||
|
}
|
||||||
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
|
default:
|
||||||
|
return GpgAutomatonHandler::AS_ERROR;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
AutomatonActionHandler action_handler =
|
||||||
|
[uid_index, reason_code, reason_text_lines](
|
||||||
|
AutomatonHandelStruct& handler, AutomatonState state) {
|
||||||
|
switch (state) {
|
||||||
|
case GpgAutomatonHandler::AS_SELECT:
|
||||||
|
return QString("uid %1").arg(uid_index);
|
||||||
|
case GpgAutomatonHandler::AS_COMMAND:
|
||||||
|
return QString("revuid");
|
||||||
|
case GpgAutomatonHandler::AS_REASON_CODE:
|
||||||
|
return QString::number(reason_code);
|
||||||
|
case GpgAutomatonHandler::AS_REASON_TEXT:
|
||||||
|
return reason_text_lines->isEmpty()
|
||||||
|
? QString("")
|
||||||
|
: QString(reason_text_lines->takeFirst().toUtf8());
|
||||||
|
case GpgAutomatonHandler::AS_REALLY_ULTIMATE:
|
||||||
|
return QString("Y");
|
||||||
|
case GpgAutomatonHandler::AS_QUIT:
|
||||||
|
return QString("quit");
|
||||||
|
case GpgAutomatonHandler::AS_SAVE:
|
||||||
|
handler.SetSuccess(true);
|
||||||
|
return QString("Y");
|
||||||
|
case GpgAutomatonHandler::AS_START:
|
||||||
|
case GpgAutomatonHandler::AS_ERROR:
|
||||||
|
return QString("");
|
||||||
|
default:
|
||||||
|
return QString("");
|
||||||
|
}
|
||||||
|
return QString("");
|
||||||
|
};
|
||||||
|
|
||||||
|
auto key_fpr = key.GetFingerprint();
|
||||||
|
AutomatonHandelStruct handel_struct(key_fpr);
|
||||||
|
handel_struct.SetHandler(next_state_handler, action_handler);
|
||||||
|
|
||||||
|
GpgData data_out;
|
||||||
|
|
||||||
|
return GpgAutomatonHandler::GetInstance(GetChannel())
|
||||||
|
.DoInteract(key, next_state_handler, action_handler);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace GpgFrontend
|
} // namespace GpgFrontend
|
||||||
|
@ -67,12 +67,27 @@ class GPGFRONTEND_CORE_EXPORT GpgUIDOperator
|
|||||||
const QString& email) -> bool;
|
const QString& email) -> bool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Revoke(Delete) UID from certain key pair
|
* @brief
|
||||||
* @param key target key pair
|
*
|
||||||
* @param uid target uid
|
* @param key
|
||||||
* @return if successful
|
* @param uid_index
|
||||||
|
* @return true
|
||||||
|
* @return false
|
||||||
*/
|
*/
|
||||||
auto RevUID(const GpgKey& key, const QString& uid) -> bool;
|
auto DeleteUID(const GpgKey& key, int uid_index) -> bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param uid_index
|
||||||
|
* @param reason_code
|
||||||
|
* @param reason_text
|
||||||
|
* @return true
|
||||||
|
* @return false
|
||||||
|
*/
|
||||||
|
auto RevokeUID(const GpgKey& key, int uid_index, int reason_code,
|
||||||
|
const QString& reason_text) -> bool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set one of a uid of a key pair as primary
|
* Set one of a uid of a key pair as primary
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
#include "core/model/GpgImportInformation.h"
|
#include "core/model/GpgImportInformation.h"
|
||||||
#include "core/utils/GpgUtils.h"
|
#include "core/utils/GpgUtils.h"
|
||||||
|
|
||||||
const char *TEST_PRIVATE_KEY_DATA = R"(
|
static const char *test_private_key_data = R"(
|
||||||
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||||
|
|
||||||
lQOYBGcSdI8BCACwi1n2Bx1v6qmQxRgrONYlmzKrSBvNyoSOdAVcTJDXYjdlNFCq
|
lQOYBGcSdI8BCACwi1n2Bx1v6qmQxRgrONYlmzKrSBvNyoSOdAVcTJDXYjdlNFCq
|
||||||
@ -110,7 +110,7 @@ namespace GpgFrontend::Test {
|
|||||||
|
|
||||||
TEST_F(GpgCoreTest, CoreDeleteSubkeyTestA) {
|
TEST_F(GpgCoreTest, CoreDeleteSubkeyTestA) {
|
||||||
auto info = GpgKeyImportExporter::GetInstance().ImportKey(
|
auto info = GpgKeyImportExporter::GetInstance().ImportKey(
|
||||||
GFBuffer(QString::fromLatin1(TEST_PRIVATE_KEY_DATA)));
|
GFBuffer(QString::fromLatin1(test_private_key_data)));
|
||||||
|
|
||||||
ASSERT_EQ(info->not_imported, 0);
|
ASSERT_EQ(info->not_imported, 0);
|
||||||
ASSERT_EQ(info->imported, 1);
|
ASSERT_EQ(info->imported, 1);
|
||||||
@ -143,7 +143,7 @@ TEST_F(GpgCoreTest, CoreDeleteSubkeyTestA) {
|
|||||||
|
|
||||||
TEST_F(GpgCoreTest, CoreSetOwnerTrustA) {
|
TEST_F(GpgCoreTest, CoreSetOwnerTrustA) {
|
||||||
auto info = GpgKeyImportExporter::GetInstance().ImportKey(
|
auto info = GpgKeyImportExporter::GetInstance().ImportKey(
|
||||||
GFBuffer(QString::fromLatin1(TEST_PRIVATE_KEY_DATA)));
|
GFBuffer(QString::fromLatin1(test_private_key_data)));
|
||||||
|
|
||||||
ASSERT_EQ(info->not_imported, 0);
|
ASSERT_EQ(info->not_imported, 0);
|
||||||
ASSERT_EQ(info->imported, 1);
|
ASSERT_EQ(info->imported, 1);
|
||||||
@ -217,7 +217,7 @@ TEST_F(GpgCoreTest, CoreSetOwnerTrustA) {
|
|||||||
|
|
||||||
TEST_F(GpgCoreTest, CoreRevokeSubkeyTestA) {
|
TEST_F(GpgCoreTest, CoreRevokeSubkeyTestA) {
|
||||||
auto info = GpgKeyImportExporter::GetInstance().ImportKey(
|
auto info = GpgKeyImportExporter::GetInstance().ImportKey(
|
||||||
GFBuffer(QString::fromLatin1(TEST_PRIVATE_KEY_DATA)));
|
GFBuffer(QString::fromLatin1(test_private_key_data)));
|
||||||
|
|
||||||
ASSERT_EQ(info->not_imported, 0);
|
ASSERT_EQ(info->not_imported, 0);
|
||||||
ASSERT_EQ(info->imported, 1);
|
ASSERT_EQ(info->imported, 1);
|
||||||
|
136
src/test/core/GpgCoreTestKeyUIDOpera.cpp
Normal file
136
src/test/core/GpgCoreTestKeyUIDOpera.cpp
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (C) 2021-2024 Saturneric <eric@bktus.com>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* The initial version of the source code is inherited from
|
||||||
|
* the gpg4usb project, which is under GPL-3.0-or-later.
|
||||||
|
*
|
||||||
|
* All the source code of GpgFrontend was modified and released by
|
||||||
|
* Saturneric <eric@bktus.com> starting on May 12, 2021.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "GpgCoreTest.h"
|
||||||
|
#include "core/GpgConstants.h"
|
||||||
|
#include "core/function/gpg/GpgKeyGetter.h"
|
||||||
|
#include "core/function/gpg/GpgKeyImportExporter.h"
|
||||||
|
#include "core/function/gpg/GpgKeyOpera.h"
|
||||||
|
#include "core/function/gpg/GpgUIDOperator.h"
|
||||||
|
#include "core/model/GpgImportInformation.h"
|
||||||
|
#include "core/utils/GpgUtils.h"
|
||||||
|
|
||||||
|
static const char *test_private_key_data = R"(
|
||||||
|
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||||
|
|
||||||
|
lHQEZ0N2exMFK4EEAAoCAwTmBGWDMqzfdx1fkGjuWHP/R6F2ZvvlolcVNJAImWKl
|
||||||
|
ew0ncmSH1/pOQ7vAud9yPnkDZfhJpcKHl1G4q/Bu5YyiAAEA5sIYAJtXCFrI5upG
|
||||||
|
Lk8XmdqGCn5c8gKsWVUikrqdKkcOLrQbZmZmZmZmKGZmZmZmKTxmZmZmQGZmZi5m
|
||||||
|
ZmY+iJkEExMIAEEWIQQwn1gjkF+wDtnB6TLy2N+l8QneRwUCZ0N2ewIbIwUJA8Jm
|
||||||
|
8wULCQgHAgIiAgYVCgkICwIEFgIDAQIeBwIXgAAKCRDy2N+l8QneR2ptAQCRE6T3
|
||||||
|
HhNp7CHVk1DkxTIj4i7Mw1Em7Cwvctr8usPhBwD/YECZLMowPLNZO4GFhIH+1Etd
|
||||||
|
GZ2d0Gbb51DUlPZUO2K0HGdnZ2dnZyhnZ2dnZyk8Z2dnZ2dAZ2dnLmdnZz6ImQQT
|
||||||
|
EwgAQRYhBDCfWCOQX7AO2cHpMvLY36XxCd5HBQJnRjCtAhsjBQkDwmbzBQsJCAcC
|
||||||
|
AiICBhUKCQgLAgQWAgMBAh4HAheAAAoJEPLY36XxCd5HaD8BAPvBCdzFSeGXyFXh
|
||||||
|
4Sn4tVpwlnJOwzC0ECGYSieaNjocAQChWIXVinXAQ5U/oslqR2+Gg1s2o8gTKVbv
|
||||||
|
ZE6T+6Vvc7QgaGhoaGhoKGhoaGhoaGgpPGhoaGhoQGhoaGguaGhoaD6ImQQTEwgA
|
||||||
|
QRYhBDCfWCOQX7AO2cHpMvLY36XxCd5HBQJnRjC2AhsjBQkDwmbzBQsJCAcCAiIC
|
||||||
|
BhUKCQgLAgQWAgMBAh4HAheAAAoJEPLY36XxCd5HqE0A/R9wq+ZobC2Iztoudcg/
|
||||||
|
eKXp1hs1D9zv7R6KkLdbB4zXAP0ch5qZnrb+U/wIuhq+oOwJknMsD/njB263eUgb
|
||||||
|
AXNh2rQdeXl5eXkoeXl5eXl5KTx5eXl5eUB5eXl5Lnl5eT6ImQQTEwgAQRYhBDCf
|
||||||
|
WCOQX7AO2cHpMvLY36XxCd5HBQJnRjDBAhsjBQkDwmbzBQsJCAcCAiICBhUKCQgL
|
||||||
|
AgQWAgMBAh4HAheAAAoJEPLY36XxCd5HcycA/RwytAvY8ryaR4qUPN8g1NSX3Dv8
|
||||||
|
SHYYu2cZJuck+lVxAQDxcyljEIZKVqOpNfWRZyqcRvE8kr64PymJTAPYOVdBuA==
|
||||||
|
=4Hms
|
||||||
|
-----END PGP PRIVATE KEY BLOCK-----
|
||||||
|
)";
|
||||||
|
|
||||||
|
namespace GpgFrontend::Test {
|
||||||
|
|
||||||
|
TEST_F(GpgCoreTest, CoreDeleteUIDTestA) {
|
||||||
|
auto info = GpgKeyImportExporter::GetInstance().ImportKey(
|
||||||
|
GFBuffer(QString::fromLatin1(test_private_key_data)));
|
||||||
|
|
||||||
|
ASSERT_EQ(info->not_imported, 0);
|
||||||
|
ASSERT_EQ(info->imported, 1);
|
||||||
|
|
||||||
|
auto key = GpgKeyGetter::GetInstance(kGpgFrontendDefaultChannel)
|
||||||
|
.GetKey("F2D8DFA5F109DE47");
|
||||||
|
ASSERT_TRUE(key.IsGood());
|
||||||
|
|
||||||
|
auto uids = key.GetUIDs();
|
||||||
|
|
||||||
|
ASSERT_EQ(uids->size(), 4);
|
||||||
|
ASSERT_EQ((*uids)[2].GetUID(), "gggggg(ggggg)<ggggg@ggg.ggg>");
|
||||||
|
|
||||||
|
auto res = GpgUIDOperator::GetInstance().DeleteUID(key, 3);
|
||||||
|
|
||||||
|
ASSERT_TRUE(res);
|
||||||
|
|
||||||
|
GpgKeyGetter::GetInstance().FlushKeyCache();
|
||||||
|
key = GpgKeyGetter::GetInstance(kGpgFrontendDefaultChannel)
|
||||||
|
.GetKey("F2D8DFA5F109DE47");
|
||||||
|
ASSERT_TRUE(key.IsGood());
|
||||||
|
|
||||||
|
uids = key.GetUIDs();
|
||||||
|
|
||||||
|
ASSERT_EQ(uids->size(), 3);
|
||||||
|
ASSERT_EQ((*uids)[2].GetUID(), "hhhhhh(hhhhhhh)<hhhhh@hhhh.hhhh>");
|
||||||
|
|
||||||
|
GpgKeyOpera::GetInstance().DeleteKey(key.GetId());
|
||||||
|
GpgKeyGetter::GetInstance().FlushKeyCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(GpgCoreTest, CoreRevokeUIDTestA) {
|
||||||
|
GpgKeyGetter::GetInstance().FlushKeyCache();
|
||||||
|
auto info = GpgKeyImportExporter::GetInstance().ImportKey(
|
||||||
|
GFBuffer(QString::fromLatin1(test_private_key_data)));
|
||||||
|
|
||||||
|
ASSERT_EQ(info->not_imported, 0);
|
||||||
|
ASSERT_EQ(info->imported, 1);
|
||||||
|
|
||||||
|
auto key = GpgKeyGetter::GetInstance(kGpgFrontendDefaultChannel)
|
||||||
|
.GetKey("F2D8DFA5F109DE47");
|
||||||
|
ASSERT_TRUE(key.IsGood());
|
||||||
|
|
||||||
|
auto uids = key.GetUIDs();
|
||||||
|
|
||||||
|
ASSERT_EQ(uids->size(), 4);
|
||||||
|
ASSERT_EQ((*uids)[2].GetUID(), "gggggg(ggggg)<ggggg@ggg.ggg>");
|
||||||
|
|
||||||
|
auto res = GpgUIDOperator::GetInstance().RevokeUID(
|
||||||
|
key, 3, 4, "H\nEEEEEL\n\n\n\nL \n0\n");
|
||||||
|
|
||||||
|
ASSERT_TRUE(res);
|
||||||
|
|
||||||
|
GpgKeyGetter::GetInstance().FlushKeyCache();
|
||||||
|
key = GpgKeyGetter::GetInstance(kGpgFrontendDefaultChannel)
|
||||||
|
.GetKey("F2D8DFA5F109DE47");
|
||||||
|
ASSERT_TRUE(key.IsGood());
|
||||||
|
|
||||||
|
uids = key.GetUIDs();
|
||||||
|
|
||||||
|
ASSERT_EQ(uids->size(), 4);
|
||||||
|
ASSERT_EQ((*uids)[2].GetUID(), "gggggg(ggggg)<ggggg@ggg.ggg>");
|
||||||
|
ASSERT_TRUE((*uids)[2].GetRevoked());
|
||||||
|
|
||||||
|
GpgKeyOpera::GetInstance().DeleteKey(key.GetId());
|
||||||
|
GpgKeyGetter::GetInstance().FlushKeyCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace GpgFrontend::Test
|
@ -32,16 +32,11 @@
|
|||||||
#include "ui_RevocationOptionsDialog.h"
|
#include "ui_RevocationOptionsDialog.h"
|
||||||
|
|
||||||
GpgFrontend::UI::RevocationOptionsDialog::RevocationOptionsDialog(
|
GpgFrontend::UI::RevocationOptionsDialog::RevocationOptionsDialog(
|
||||||
QWidget *parent)
|
const QStringList& codes, QWidget* parent)
|
||||||
: GeneralDialog("RevocationOptionsDialog", parent),
|
: GeneralDialog("RevocationOptionsDialog", parent),
|
||||||
ui_(GpgFrontend::SecureCreateSharedObject<Ui_RevocationOptionsDialog>()) {
|
ui_(GpgFrontend::SecureCreateSharedObject<Ui_RevocationOptionsDialog>()) {
|
||||||
ui_->setupUi(this);
|
ui_->setupUi(this);
|
||||||
|
|
||||||
QStringList codes;
|
|
||||||
|
|
||||||
codes << tr("0 -> No Reason.") << tr("1 -> This key is no more safe.")
|
|
||||||
<< tr("2 -> Key is outdated.") << tr("3 -> Key is no longer used");
|
|
||||||
|
|
||||||
ui_->rRcodeComboBox->addItems(codes);
|
ui_->rRcodeComboBox->addItems(codes);
|
||||||
|
|
||||||
ui_->revocationReasonCodeLabel->setText(tr("Revocation Reason (Code)"));
|
ui_->revocationReasonCodeLabel->setText(tr("Revocation Reason (Code)"));
|
||||||
|
@ -36,7 +36,7 @@ namespace GpgFrontend::UI {
|
|||||||
class RevocationOptionsDialog : public GeneralDialog {
|
class RevocationOptionsDialog : public GeneralDialog {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit RevocationOptionsDialog(QWidget *parent);
|
explicit RevocationOptionsDialog(const QStringList& codes, QWidget* parent);
|
||||||
|
|
||||||
[[nodiscard]] auto Code() const -> int;
|
[[nodiscard]] auto Code() const -> int;
|
||||||
|
|
||||||
|
@ -463,7 +463,10 @@ void KeyPairOperaTab::slot_update_key_from_server() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void KeyPairOperaTab::slot_gen_revoke_cert() {
|
void KeyPairOperaTab::slot_gen_revoke_cert() {
|
||||||
auto* revocation_options_dialog = new RevocationOptionsDialog(this);
|
QStringList codes;
|
||||||
|
codes << tr("0 -> No Reason.") << tr("1 -> This key is no more safe.")
|
||||||
|
<< tr("2 -> Key is outdated.") << tr("3 -> Key is no longer used");
|
||||||
|
auto* revocation_options_dialog = new RevocationOptionsDialog(codes, this);
|
||||||
|
|
||||||
connect(revocation_options_dialog,
|
connect(revocation_options_dialog,
|
||||||
&RevocationOptionsDialog::SignalRevokeOptionAccepted, this,
|
&RevocationOptionsDialog::SignalRevokeOptionAccepted, this,
|
||||||
|
@ -520,7 +520,7 @@ void KeyPairSubkeyTab::slot_revoke_subkey() {
|
|||||||
const auto subkeys = key_.GetSubKeys();
|
const auto subkeys = key_.GetSubKeys();
|
||||||
|
|
||||||
QString message = tr("<h3>Revoke Subkey Confirmation</h3><br />"
|
QString message = tr("<h3>Revoke Subkey Confirmation</h3><br />"
|
||||||
"<b>KeyID:</b> %1<br />2<br />"
|
"<b>KeyID:</b> %1<br /><br />"
|
||||||
"Revoking a subkey will make it permanently unusable. "
|
"Revoking a subkey will make it permanently unusable. "
|
||||||
"This action is <b>irreversible</b>.<br />"
|
"This action is <b>irreversible</b>.<br />"
|
||||||
"Are you sure you want to revoke this subkey?")
|
"Are you sure you want to revoke this subkey?")
|
||||||
@ -547,7 +547,10 @@ void KeyPairSubkeyTab::slot_revoke_subkey() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* revocation_options_dialog = new RevocationOptionsDialog(this);
|
QStringList codes;
|
||||||
|
codes << tr("0 -> No Reason.") << tr("1 -> This key is no more safe.")
|
||||||
|
<< tr("2 -> Key is outdated.") << tr("3 -> Key is no longer used");
|
||||||
|
auto* revocation_options_dialog = new RevocationOptionsDialog(codes, this);
|
||||||
|
|
||||||
connect(revocation_options_dialog,
|
connect(revocation_options_dialog,
|
||||||
&RevocationOptionsDialog::SignalRevokeOptionAccepted, this,
|
&RevocationOptionsDialog::SignalRevokeOptionAccepted, this,
|
||||||
|
@ -33,6 +33,9 @@
|
|||||||
#include "core/function/gpg/GpgKeyManager.h"
|
#include "core/function/gpg/GpgKeyManager.h"
|
||||||
#include "core/function/gpg/GpgUIDOperator.h"
|
#include "core/function/gpg/GpgUIDOperator.h"
|
||||||
#include "ui/UISignalStation.h"
|
#include "ui/UISignalStation.h"
|
||||||
|
#include "ui/dialog/RevocationOptionsDialog.h"
|
||||||
|
#include "ui/dialog/keypair_details/KeyNewUIDDialog.h"
|
||||||
|
#include "ui/dialog/keypair_details/KeyUIDSignDialog.h"
|
||||||
#include "ui/widgets/TOFUInfoPage.h"
|
#include "ui/widgets/TOFUInfoPage.h"
|
||||||
|
|
||||||
namespace GpgFrontend::UI {
|
namespace GpgFrontend::UI {
|
||||||
@ -47,24 +50,17 @@ KeyPairUIDTab::KeyPairUIDTab(int channel, const QString& key_id,
|
|||||||
|
|
||||||
create_uid_list();
|
create_uid_list();
|
||||||
create_sign_list();
|
create_sign_list();
|
||||||
create_manage_uid_menu();
|
|
||||||
create_uid_popup_menu();
|
create_uid_popup_menu();
|
||||||
create_sign_popup_menu();
|
create_sign_popup_menu();
|
||||||
|
|
||||||
auto* uid_buttons_layout = new QGridLayout();
|
auto* uid_buttons_layout = new QHBoxLayout();
|
||||||
|
|
||||||
auto* add_uid_button = new QPushButton(tr("New UID"));
|
auto* add_uid_button = new QPushButton(tr("New UID"));
|
||||||
auto* manage_uid_button = new QPushButton(tr("UID Management"));
|
|
||||||
|
|
||||||
if (m_key_.IsHasMasterKey()) {
|
if (!m_key_.IsHasMasterKey()) {
|
||||||
manage_uid_button->setMenu(manage_selected_uid_menu_);
|
|
||||||
} else {
|
|
||||||
add_uid_button->setDisabled(true);
|
add_uid_button->setDisabled(true);
|
||||||
manage_uid_button->setDisabled(true);
|
|
||||||
}
|
}
|
||||||
|
uid_buttons_layout->addWidget(add_uid_button);
|
||||||
uid_buttons_layout->addWidget(add_uid_button, 0, 1);
|
|
||||||
uid_buttons_layout->addWidget(manage_uid_button, 0, 2);
|
|
||||||
|
|
||||||
auto* grid_layout = new QGridLayout();
|
auto* grid_layout = new QGridLayout();
|
||||||
|
|
||||||
@ -200,14 +196,12 @@ void KeyPairUIDTab::slot_refresh_uid_list() {
|
|||||||
auto* tmp2 = new QTableWidgetItem(uid.GetComment());
|
auto* tmp2 = new QTableWidgetItem(uid.GetComment());
|
||||||
uid_list_->setItem(row, 3, tmp2);
|
uid_list_->setItem(row, 3, tmp2);
|
||||||
|
|
||||||
auto* tmp3 = new QTableWidgetItem(QString::number(row));
|
auto* tmp3 = new QTableWidgetItem(QString::number(row + 1));
|
||||||
tmp3->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled |
|
tmp3->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
|
||||||
Qt::ItemIsSelectable);
|
|
||||||
tmp3->setTextAlignment(Qt::AlignCenter);
|
tmp3->setTextAlignment(Qt::AlignCenter);
|
||||||
tmp3->setCheckState(Qt::Unchecked);
|
|
||||||
uid_list_->setItem(row, 0, tmp3);
|
uid_list_->setItem(row, 0, tmp3);
|
||||||
|
|
||||||
if (!row) {
|
if (row == 0) {
|
||||||
for (auto i = 0; i < uid_list_->columnCount(); i++) {
|
for (auto i = 0; i < uid_list_->columnCount(); i++) {
|
||||||
uid_list_->item(row, i)->setForeground(QColor(65, 105, 255));
|
uid_list_->item(row, i)->setForeground(QColor(65, 105, 255));
|
||||||
}
|
}
|
||||||
@ -304,45 +298,13 @@ void KeyPairUIDTab::slot_refresh_sig_list() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void KeyPairUIDTab::slot_add_sign() {
|
void KeyPairUIDTab::slot_add_sign() {
|
||||||
auto selected_uids = get_uid_checked();
|
const auto& target_uid = get_selected_uid();
|
||||||
|
|
||||||
if (selected_uids->empty()) {
|
|
||||||
QMessageBox::information(
|
|
||||||
nullptr, tr("Invalid Operation"),
|
|
||||||
tr("Please select one or more UIDs before doing this operation."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* key_sign_dialog = new KeyUIDSignDialog(
|
auto* key_sign_dialog = new KeyUIDSignDialog(
|
||||||
current_gpg_context_channel_, m_key_, std::move(selected_uids), this);
|
current_gpg_context_channel_, m_key_, target_uid.GetUID(), this);
|
||||||
key_sign_dialog->show();
|
key_sign_dialog->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto KeyPairUIDTab::get_uid_checked() -> UIDArgsListPtr {
|
|
||||||
auto selected_uids = std::make_unique<UIDArgsList>();
|
|
||||||
for (int i = 0; i < uid_list_->rowCount(); i++) {
|
|
||||||
if (uid_list_->item(i, 0)->checkState() == Qt::Checked) {
|
|
||||||
selected_uids->push_back(buffered_uids_[i].GetUID());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return selected_uids;
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyPairUIDTab::create_manage_uid_menu() {
|
|
||||||
manage_selected_uid_menu_ = new QMenu(this);
|
|
||||||
|
|
||||||
auto* sign_uid_act = new QAction(tr("Sign Selected UID(s)"), this);
|
|
||||||
connect(sign_uid_act, &QAction::triggered, this,
|
|
||||||
&KeyPairUIDTab::slot_add_sign);
|
|
||||||
auto* del_uid_act = new QAction(tr("Delete Selected UID(s)"), this);
|
|
||||||
connect(del_uid_act, &QAction::triggered, this, &KeyPairUIDTab::slot_del_uid);
|
|
||||||
|
|
||||||
if (m_key_.IsHasMasterKey()) {
|
|
||||||
manage_selected_uid_menu_->addAction(sign_uid_act);
|
|
||||||
manage_selected_uid_menu_->addAction(del_uid_act);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyPairUIDTab::slot_add_uid() {
|
void KeyPairUIDTab::slot_add_uid() {
|
||||||
auto* key_new_uid_dialog =
|
auto* key_new_uid_dialog =
|
||||||
new KeyNewUIDDialog(current_gpg_context_channel_, m_key_.GetId(), this);
|
new KeyNewUIDDialog(current_gpg_context_channel_, m_key_.GetId(), this);
|
||||||
@ -364,57 +326,58 @@ void KeyPairUIDTab::slot_add_uid_result(int result) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void KeyPairUIDTab::slot_del_uid() {
|
void KeyPairUIDTab::slot_del_uid() {
|
||||||
auto selected_uids = get_uid_checked();
|
const auto& target_uid = get_selected_uid();
|
||||||
|
|
||||||
if (selected_uids->empty()) {
|
auto keynames = QString();
|
||||||
QMessageBox::information(
|
|
||||||
nullptr, tr("Invalid Operation"),
|
keynames.append(target_uid.GetUID().toHtmlEscaped());
|
||||||
tr("Please select one or more UIDs before doing this operation."));
|
keynames.append("<br/>");
|
||||||
return;
|
|
||||||
|
int index = 1;
|
||||||
|
for (const auto& uid : buffered_uids_) {
|
||||||
|
if (uid.GetUID() == target_uid.GetUID()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString keynames;
|
if (index == 1) {
|
||||||
for (auto& uid : *selected_uids) {
|
QMessageBox::information(nullptr, tr("Invalid Operation"),
|
||||||
keynames.append(uid);
|
tr("Cannot delete the Primary UID."));
|
||||||
keynames.append("<br/>");
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret = QMessageBox::warning(
|
int ret = QMessageBox::warning(
|
||||||
this, tr("Deleting UIDs"),
|
this, tr("Deleting UIDs"),
|
||||||
"<b>" +
|
"<b>" +
|
||||||
QString(
|
QString(
|
||||||
tr("Are you sure that you want to delete the following UIDs?")) +
|
tr("Are you sure that you want to delete the following UID?")) +
|
||||||
"</b><br/><br/>" + keynames + +"<br/>" +
|
"</b><br/><br/>" + target_uid.GetUID().toHtmlEscaped() + +"<br/>" +
|
||||||
tr("The action can not be undone."),
|
tr("The action can not be undone."),
|
||||||
QMessageBox::No | QMessageBox::Yes);
|
QMessageBox::No | QMessageBox::Yes);
|
||||||
|
|
||||||
if (ret == QMessageBox::Yes) {
|
if (ret == QMessageBox::Yes) {
|
||||||
for (const auto& uid : *selected_uids) {
|
|
||||||
if (!GpgUIDOperator::GetInstance(current_gpg_context_channel_)
|
if (!GpgUIDOperator::GetInstance(current_gpg_context_channel_)
|
||||||
.RevUID(m_key_, uid)) {
|
.DeleteUID(m_key_, index)) {
|
||||||
QMessageBox::critical(
|
QMessageBox::critical(
|
||||||
nullptr, tr("Operation Failed"),
|
nullptr, tr("Operation Failed"),
|
||||||
tr("An error occurred during the delete %1 operation.").arg(uid));
|
tr("An error occurred during the delete %1 operation.")
|
||||||
}
|
.arg(target_uid.GetUID().toHtmlEscaped()));
|
||||||
}
|
}
|
||||||
emit SignalUpdateUIDInfo();
|
emit SignalUpdateUIDInfo();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyPairUIDTab::slot_set_primary_uid() {
|
void KeyPairUIDTab::slot_set_primary_uid() {
|
||||||
auto selected_uids = get_uid_selected();
|
const auto& target_uid = get_selected_uid();
|
||||||
|
|
||||||
if (selected_uids->empty()) {
|
if (target_uid.GetUID() == buffered_uids_.front().GetUID()) {
|
||||||
auto* empty_uid_msg = new QMessageBox();
|
|
||||||
empty_uid_msg->setText(
|
|
||||||
"Please select one UID before doing this operation.");
|
|
||||||
empty_uid_msg->exec();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString keynames;
|
QString keynames;
|
||||||
|
|
||||||
keynames.append(selected_uids->front());
|
keynames.append(target_uid.GetUID().toHtmlEscaped());
|
||||||
keynames.append("<br/>");
|
keynames.append("<br/>");
|
||||||
|
|
||||||
int ret = QMessageBox::warning(
|
int ret = QMessageBox::warning(
|
||||||
@ -424,26 +387,16 @@ void KeyPairUIDTab::slot_set_primary_uid() {
|
|||||||
tr("The action can not be undone."),
|
tr("The action can not be undone."),
|
||||||
QMessageBox::No | QMessageBox::Yes);
|
QMessageBox::No | QMessageBox::Yes);
|
||||||
|
|
||||||
if (ret == QMessageBox::Yes) {
|
if (ret != QMessageBox::Yes) return;
|
||||||
|
|
||||||
if (!GpgUIDOperator::GetInstance(current_gpg_context_channel_)
|
if (!GpgUIDOperator::GetInstance(current_gpg_context_channel_)
|
||||||
.SetPrimaryUID(m_key_, selected_uids->front())) {
|
.SetPrimaryUID(m_key_, target_uid.GetUID())) {
|
||||||
QMessageBox::critical(nullptr, tr("Operation Failed"),
|
QMessageBox::critical(nullptr, tr("Operation Failed"),
|
||||||
tr("An error occurred during the operation."));
|
tr("An error occurred during the operation."));
|
||||||
} else {
|
} else {
|
||||||
emit SignalUpdateUIDInfo();
|
emit SignalUpdateUIDInfo();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
auto KeyPairUIDTab::get_uid_selected() -> UIDArgsListPtr {
|
|
||||||
auto uids = std::make_unique<UIDArgsList>();
|
|
||||||
for (int i = 0; i < uid_list_->rowCount(); i++) {
|
|
||||||
if (uid_list_->item(i, 0)->isSelected()) {
|
|
||||||
uids->push_back(buffered_uids_[i].GetUID());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return uids;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto KeyPairUIDTab::get_sign_selected() -> SignIdArgsListPtr {
|
auto KeyPairUIDTab::get_sign_selected() -> SignIdArgsListPtr {
|
||||||
auto signatures = std::make_unique<SignIdArgsList>();
|
auto signatures = std::make_unique<SignIdArgsList>();
|
||||||
@ -459,79 +412,48 @@ auto KeyPairUIDTab::get_sign_selected() -> SignIdArgsListPtr {
|
|||||||
void KeyPairUIDTab::create_uid_popup_menu() {
|
void KeyPairUIDTab::create_uid_popup_menu() {
|
||||||
uid_popup_menu_ = new QMenu(this);
|
uid_popup_menu_ = new QMenu(this);
|
||||||
|
|
||||||
auto* ser_primary_uid_act = new QAction(tr("Set As Primary"), this);
|
set_primary_uid_act_ = new QAction(tr("Set As Primary"), this);
|
||||||
connect(ser_primary_uid_act, &QAction::triggered, this,
|
connect(set_primary_uid_act_, &QAction::triggered, this,
|
||||||
&KeyPairUIDTab::slot_set_primary_uid);
|
&KeyPairUIDTab::slot_set_primary_uid);
|
||||||
auto* sign_uid_act = new QAction(tr("Sign UID"), this);
|
sign_uid_act_ = new QAction(tr("Sign UID"), this);
|
||||||
connect(sign_uid_act, &QAction::triggered, this,
|
connect(sign_uid_act_, &QAction::triggered, this,
|
||||||
&KeyPairUIDTab::slot_add_sign_single);
|
&KeyPairUIDTab::slot_add_sign_single);
|
||||||
auto* del_uid_act = new QAction(tr("Delete UID"), this);
|
rev_uid_act_ = new QAction(tr("Revoke UID"), this);
|
||||||
connect(del_uid_act, &QAction::triggered, this,
|
connect(rev_uid_act_, &QAction::triggered, this,
|
||||||
&KeyPairUIDTab::slot_del_uid_single);
|
&KeyPairUIDTab::slot_rev_uid);
|
||||||
|
del_uid_act_ = new QAction(tr("Delete UID"), this);
|
||||||
|
connect(del_uid_act_, &QAction::triggered, this,
|
||||||
|
&KeyPairUIDTab::slot_del_uid);
|
||||||
|
|
||||||
if (m_key_.IsHasMasterKey()) {
|
if (m_key_.IsHasMasterKey()) {
|
||||||
uid_popup_menu_->addAction(ser_primary_uid_act);
|
uid_popup_menu_->addAction(set_primary_uid_act_);
|
||||||
uid_popup_menu_->addAction(sign_uid_act);
|
uid_popup_menu_->addAction(sign_uid_act_);
|
||||||
uid_popup_menu_->addAction(del_uid_act);
|
uid_popup_menu_->addAction(rev_uid_act_);
|
||||||
|
uid_popup_menu_->addAction(del_uid_act_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyPairUIDTab::contextMenuEvent(QContextMenuEvent* event) {
|
void KeyPairUIDTab::contextMenuEvent(QContextMenuEvent* event) {
|
||||||
if (uid_list_->selectedItems().length() > 0 &&
|
if (uid_list_->selectedItems().length() > 0 &&
|
||||||
sig_list_->selectedItems().isEmpty()) {
|
sig_list_->selectedItems().isEmpty()) {
|
||||||
|
auto is_primary_uid =
|
||||||
|
get_selected_uid().GetUID() == buffered_uids_.front().GetUID();
|
||||||
|
set_primary_uid_act_->setDisabled(is_primary_uid);
|
||||||
|
rev_uid_act_->setDisabled(is_primary_uid);
|
||||||
|
del_uid_act_->setDisabled(is_primary_uid);
|
||||||
|
|
||||||
uid_popup_menu_->exec(event->globalPos());
|
uid_popup_menu_->exec(event->globalPos());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyPairUIDTab::slot_add_sign_single() {
|
void KeyPairUIDTab::slot_add_sign_single() {
|
||||||
auto selected_uids = get_uid_selected();
|
const auto& target_uid = get_selected_uid();
|
||||||
|
|
||||||
if (selected_uids->empty()) {
|
|
||||||
QMessageBox::information(
|
|
||||||
nullptr, tr("Invalid Operation"),
|
|
||||||
tr("Please select one UID before doing this operation."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* key_sign_dialog = new KeyUIDSignDialog(
|
auto* key_sign_dialog = new KeyUIDSignDialog(
|
||||||
current_gpg_context_channel_, m_key_, std::move(selected_uids), this);
|
current_gpg_context_channel_, m_key_, target_uid.GetUID(), this);
|
||||||
key_sign_dialog->show();
|
key_sign_dialog->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyPairUIDTab::slot_del_uid_single() {
|
|
||||||
auto selected_uids = get_uid_selected();
|
|
||||||
if (selected_uids->empty()) {
|
|
||||||
QMessageBox::information(
|
|
||||||
nullptr, tr("Invalid Operation"),
|
|
||||||
tr("Please select one UID before doing this operation."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString keynames;
|
|
||||||
|
|
||||||
keynames.append(selected_uids->front());
|
|
||||||
keynames.append("<br/>");
|
|
||||||
|
|
||||||
int ret = QMessageBox::warning(
|
|
||||||
this, tr("Deleting UID"),
|
|
||||||
"<b>" +
|
|
||||||
QString(
|
|
||||||
tr("Are you sure that you want to delete the following uid?")) +
|
|
||||||
"</b><br/><br/>" + keynames + +"<br/>" +
|
|
||||||
tr("The action can not be undone."),
|
|
||||||
QMessageBox::No | QMessageBox::Yes);
|
|
||||||
|
|
||||||
if (ret == QMessageBox::Yes) {
|
|
||||||
if (!GpgUIDOperator::GetInstance(current_gpg_context_channel_)
|
|
||||||
.RevUID(m_key_, selected_uids->front())) {
|
|
||||||
QMessageBox::critical(nullptr, tr("Operation Failed"),
|
|
||||||
tr("An error occurred during the operation."));
|
|
||||||
} else {
|
|
||||||
emit SignalUpdateUIDInfo();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyPairUIDTab::create_sign_popup_menu() {
|
void KeyPairUIDTab::create_sign_popup_menu() {
|
||||||
sign_popup_menu_ = new QMenu(this);
|
sign_popup_menu_ = new QMenu(this);
|
||||||
|
|
||||||
@ -595,4 +517,78 @@ void KeyPairUIDTab::slot_refresh_key() {
|
|||||||
this->slot_refresh_sig_list();
|
this->slot_refresh_sig_list();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KeyPairUIDTab::slot_rev_uid() {
|
||||||
|
const auto& target_uid = get_selected_uid();
|
||||||
|
|
||||||
|
if (target_uid.GetUID() == buffered_uids_.front().GetUID()) {
|
||||||
|
QMessageBox::information(
|
||||||
|
nullptr, tr("Invalid Operation"),
|
||||||
|
tr("Please select one UID before doing this operation."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto uids = m_key_.GetUIDs();
|
||||||
|
|
||||||
|
QString message = tr("<h3>Revoke UID Confirmation</h3><br />"
|
||||||
|
"<b>UID:</b> %1<br /><br />"
|
||||||
|
"Revoking a UID will make it permanently unusable. "
|
||||||
|
"This action is <b>irreversible</b>.<br />"
|
||||||
|
"Are you sure you want to revoke this UID?")
|
||||||
|
.arg(target_uid.GetUID().toHtmlEscaped());
|
||||||
|
|
||||||
|
int ret = QMessageBox::warning(this, tr("Revoke UID"), message,
|
||||||
|
QMessageBox::Cancel | QMessageBox::Yes,
|
||||||
|
QMessageBox::Cancel);
|
||||||
|
|
||||||
|
if (ret != QMessageBox::Yes) return;
|
||||||
|
|
||||||
|
int index = 1;
|
||||||
|
for (const auto& uid : buffered_uids_) {
|
||||||
|
if (uid.GetUID() == target_uid.GetUID()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index == 1) {
|
||||||
|
QMessageBox::information(nullptr, tr("Invalid Operation"),
|
||||||
|
tr("Cannot delete the Primary UID."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList codes;
|
||||||
|
codes << tr("0 -> No Reason.") << tr("4 -> User ID is no longer valid.");
|
||||||
|
auto* revocation_options_dialog = new RevocationOptionsDialog(codes, this);
|
||||||
|
|
||||||
|
connect(revocation_options_dialog,
|
||||||
|
&RevocationOptionsDialog::SignalRevokeOptionAccepted, this,
|
||||||
|
[key = m_key_, index, channel = current_gpg_context_channel_, this](
|
||||||
|
int code, const QString& text) {
|
||||||
|
auto res = GpgUIDOperator::GetInstance(channel).RevokeUID(
|
||||||
|
key, index, code == 1 ? 4 : 0, text);
|
||||||
|
if (!res) {
|
||||||
|
QMessageBox::critical(
|
||||||
|
nullptr, tr("Revocation Failed"),
|
||||||
|
tr("Failed to revoke the UID. Please try again."));
|
||||||
|
} else {
|
||||||
|
QMessageBox::information(
|
||||||
|
nullptr, tr("Revocation Successful"),
|
||||||
|
tr("The UID has been successfully revoked."));
|
||||||
|
emit SignalUpdateUIDInfo();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
revocation_options_dialog->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto KeyPairUIDTab::get_selected_uid() -> const GpgUID& {
|
||||||
|
int row = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < uid_list_->rowCount(); i++) {
|
||||||
|
if (uid_list_->item(row, 0)->isSelected()) break;
|
||||||
|
row++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffered_uids_[row];
|
||||||
|
}
|
||||||
} // namespace GpgFrontend::UI
|
} // namespace GpgFrontend::UI
|
||||||
|
@ -28,9 +28,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "KeyNewUIDDialog.h"
|
#include "core/GpgModel.h"
|
||||||
#include "KeyUIDSignDialog.h"
|
|
||||||
#include "core/function/gpg/GpgContext.h"
|
|
||||||
#include "ui/GpgFrontendUI.h"
|
#include "ui/GpgFrontendUI.h"
|
||||||
|
|
||||||
namespace GpgFrontend::UI {
|
namespace GpgFrontend::UI {
|
||||||
@ -55,68 +53,13 @@ class KeyPairUIDTab : public QWidget {
|
|||||||
*/
|
*/
|
||||||
void SignalUpdateUIDInfo();
|
void SignalUpdateUIDInfo();
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
int current_gpg_context_channel_;
|
|
||||||
GpgKey m_key_;
|
|
||||||
QTableWidget* uid_list_{}; ///<
|
|
||||||
QTableWidget* sig_list_{}; ///<
|
|
||||||
QTabWidget* tofu_tabs_{}; ///<
|
|
||||||
QMenu* manage_selected_uid_menu_{}; ///<
|
|
||||||
QMenu* uid_popup_menu_{}; ///<
|
|
||||||
QMenu* sign_popup_menu_{}; ///<
|
|
||||||
std::vector<GpgUID> buffered_uids_; ///<
|
|
||||||
std::vector<GpgKeySignature> buffered_signatures_; ///<
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create a uid list object
|
* @brief
|
||||||
*
|
*
|
||||||
|
* @param event
|
||||||
*/
|
*/
|
||||||
void create_uid_list();
|
void contextMenuEvent(QContextMenuEvent* event) override;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Create a sign list object
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void create_sign_list();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Create a manage uid menu object
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void create_manage_uid_menu();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Create a uid popup menu object
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void create_uid_popup_menu();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Create a sign popup menu object
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void create_sign_popup_menu();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the uid checked object
|
|
||||||
*
|
|
||||||
* @return UIDArgsListPtr
|
|
||||||
*/
|
|
||||||
UIDArgsListPtr get_uid_checked();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the uid selected object
|
|
||||||
*
|
|
||||||
* @return UIDArgsListPtr
|
|
||||||
*/
|
|
||||||
UIDArgsListPtr get_uid_selected();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the sign selected object
|
|
||||||
*
|
|
||||||
* @return SignIdArgsListPtr
|
|
||||||
*/
|
|
||||||
SignIdArgsListPtr get_sign_selected();
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
@ -166,7 +109,7 @@ class KeyPairUIDTab : public QWidget {
|
|||||||
* @brief
|
* @brief
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void slot_del_uid_single();
|
void slot_rev_uid();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief
|
* @brief
|
||||||
@ -193,13 +136,59 @@ class KeyPairUIDTab : public QWidget {
|
|||||||
*/
|
*/
|
||||||
static void slot_add_uid_result(int result);
|
static void slot_add_uid_result(int result);
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
|
int current_gpg_context_channel_;
|
||||||
|
GpgKey m_key_;
|
||||||
|
QTableWidget* uid_list_{}; ///<
|
||||||
|
QTableWidget* sig_list_{}; ///<
|
||||||
|
QTabWidget* tofu_tabs_{}; ///<
|
||||||
|
QMenu* uid_popup_menu_{}; ///<
|
||||||
|
QMenu* sign_popup_menu_{}; ///<
|
||||||
|
std::vector<GpgUID> buffered_uids_; ///<
|
||||||
|
std::vector<GpgKeySignature> buffered_signatures_; ///<
|
||||||
|
|
||||||
|
QAction* set_primary_uid_act_;
|
||||||
|
QAction* sign_uid_act_;
|
||||||
|
QAction* rev_uid_act_;
|
||||||
|
QAction* del_uid_act_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief
|
* @brief Create a uid list object
|
||||||
*
|
*
|
||||||
* @param event
|
|
||||||
*/
|
*/
|
||||||
void contextMenuEvent(QContextMenuEvent* event) override;
|
void create_uid_list();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a sign list object
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void create_sign_list();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a uid popup menu object
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void create_uid_popup_menu();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a sign popup menu object
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void create_sign_popup_menu();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the sign selected object
|
||||||
|
*
|
||||||
|
* @return SignIdArgsListPtr
|
||||||
|
*/
|
||||||
|
auto get_sign_selected() -> SignIdArgsListPtr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the sign selected object
|
||||||
|
*
|
||||||
|
* @return SignIdArgsListPtr
|
||||||
|
*/
|
||||||
|
auto get_selected_uid() -> const GpgUID&;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace GpgFrontend::UI
|
} // namespace GpgFrontend::UI
|
||||||
|
@ -36,10 +36,10 @@
|
|||||||
namespace GpgFrontend::UI {
|
namespace GpgFrontend::UI {
|
||||||
|
|
||||||
KeyUIDSignDialog::KeyUIDSignDialog(int channel, const GpgKey& key,
|
KeyUIDSignDialog::KeyUIDSignDialog(int channel, const GpgKey& key,
|
||||||
UIDArgsListPtr uid, QWidget* parent)
|
const QString& uid, QWidget* parent)
|
||||||
: GeneralDialog(typeid(KeyUIDSignDialog).name(), parent),
|
: GeneralDialog(typeid(KeyUIDSignDialog).name(), parent),
|
||||||
current_gpg_context_channel_(channel),
|
current_gpg_context_channel_(channel),
|
||||||
m_uids_(std::move(uid)),
|
m_uid_(uid),
|
||||||
m_key_(key) {
|
m_key_(key) {
|
||||||
assert(m_key_.IsGood());
|
assert(m_key_.IsGood());
|
||||||
|
|
||||||
@ -114,14 +114,12 @@ void KeyUIDSignDialog::slot_sign_key(bool clicked) {
|
|||||||
|
|
||||||
auto expires = std::make_unique<QDateTime>(expires_edit_->dateTime());
|
auto expires = std::make_unique<QDateTime>(expires_edit_->dateTime());
|
||||||
|
|
||||||
for (const auto& uid : *m_uids_) {
|
|
||||||
// Sign For mKey
|
// Sign For mKey
|
||||||
if (!GpgKeyManager::GetInstance(current_gpg_context_channel_)
|
if (!GpgKeyManager::GetInstance(current_gpg_context_channel_)
|
||||||
.SignKey(m_key_, *keys, uid, expires)) {
|
.SignKey(m_key_, *keys, m_uid_, expires)) {
|
||||||
QMessageBox::critical(
|
QMessageBox::critical(
|
||||||
nullptr, tr("Unsuccessful Operation"),
|
nullptr, tr("Unsuccessful Operation"),
|
||||||
tr("Signature operation failed for UID %1").arg(uid));
|
tr("Signature operation failed for UID %1").arg(m_uid_));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QMessageBox::information(
|
QMessageBox::information(
|
||||||
|
@ -45,7 +45,7 @@ class KeyUIDSignDialog : public GeneralDialog {
|
|||||||
* @param uid
|
* @param uid
|
||||||
* @param parent
|
* @param parent
|
||||||
*/
|
*/
|
||||||
explicit KeyUIDSignDialog(int channel, const GpgKey& key, UIDArgsListPtr uid,
|
explicit KeyUIDSignDialog(int channel, const GpgKey& key, const QString& uid,
|
||||||
QWidget* parent = nullptr);
|
QWidget* parent = nullptr);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
@ -61,7 +61,7 @@ class KeyUIDSignDialog : public GeneralDialog {
|
|||||||
QPushButton* sign_key_button_; ///<
|
QPushButton* sign_key_button_; ///<
|
||||||
QDateTimeEdit* expires_edit_; ///<
|
QDateTimeEdit* expires_edit_; ///<
|
||||||
QCheckBox* non_expire_check_; ///<
|
QCheckBox* non_expire_check_; ///<
|
||||||
UIDArgsListPtr m_uids_; ///<
|
QString m_uid_; ///<
|
||||||
|
|
||||||
const GpgKey& m_key_; ///<
|
const GpgKey& m_key_; ///<
|
||||||
|
|
||||||
|
@ -425,7 +425,7 @@ class MainWindow : public GeneralMainWindow {
|
|||||||
* @details Disable tab related actions, if number of tabs is 0.
|
* @details Disable tab related actions, if number of tabs is 0.
|
||||||
* @param number number of the opened tabs and -1, if no tab is opened
|
* @param number number of the opened tabs and -1, if no tab is opened
|
||||||
*/
|
*/
|
||||||
void slot_switch_menu_control_mode(int number);
|
void slot_switch_menu_control_mode(int);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @details called when need to upgrade.
|
* @details called when need to upgrade.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user