diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/CMakeLists.txt | 18 | ||||
-rw-r--r-- | src/gpg/GpgContext.cpp | 9 | ||||
-rw-r--r-- | src/gpg/GpgFileOpera.cpp | 2 | ||||
-rw-r--r-- | src/gpg/GpgUID.cpp | 26 | ||||
-rw-r--r-- | src/server/CMakeLists.txt | 6 | ||||
-rw-r--r-- | src/server/ComUtils.cpp | 81 | ||||
-rwxr-xr-x | src/ui/FileEncryptionDialog.cpp | 2 | ||||
-rw-r--r-- | src/ui/KeyUploadDialog.cpp | 2 | ||||
-rwxr-xr-x | src/ui/SettingsDialog.cpp | 166 | ||||
-rw-r--r-- | src/ui/ShowCopyDialog.cpp | 26 | ||||
-rw-r--r-- | src/ui/main_window/MainWindowSlotFunction.cpp | 193 | ||||
-rw-r--r-- | src/ui/widgets/EditorPage.cpp | 2 | ||||
-rw-r--r-- | src/ui/widgets/InfoBoardWidget.cpp | 3 | ||||
-rw-r--r-- | src/ui/widgets/KeyList.cpp | 148 |
14 files changed, 543 insertions, 141 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ad56423d..cdd0bfe7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,8 +1,7 @@ -set(ALL_SOURCE_FILE) - add_subdirectory(gpg) add_subdirectory(ui) add_subdirectory(smtp) +add_subdirectory(server) aux_source_directory(. BASE_SOURCE) @@ -121,23 +120,26 @@ else() add_executable(${AppName} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS}) endif() +set(GPGFRONTEND_LIBS smtp gpgfrontend-ui server gpg) +set(QT_DEPENDENCY_LIBS Qt5::Network Qt5::PrintSupport Qt5::Widgets Qt5::Test Qt5::Core) + IF (MINGW) message(STATUS "Link Application Static Library For MINGW") target_link_libraries(${AppName} - smtp gpgfrontend-ui gpg - Qt5::Network Qt5::PrintSupport Qt5::Widgets Qt5::Test Qt5::Core + ${GPGFRONTEND_LIBS} + ${QT_DEPENDENCY_LIBS} crypto ssl) elseif(APPLE) message(STATUS "Link Application Static Library For macOS") target_link_libraries(${AppName} - smtp gpgfrontend-ui gpg - Qt5::Network Qt5::PrintSupport Qt5::Widgets Qt5::Test Qt5::Core + ${GPGFRONTEND_LIBS} + ${QT_DEPENDENCY_LIBS} crypto ssl) else() message(STATUS "Link Application Static Library For UNIX") target_link_libraries(${AppName} - smtp gpgfrontend-ui gpg - Qt5::Network Qt5::PrintSupport Qt5::Widgets Qt5::Test Qt5::Core + ${GPGFRONTEND_LIBS} + ${QT_DEPENDENCY_LIBS} crypto ssl pthread) endif() diff --git a/src/gpg/GpgContext.cpp b/src/gpg/GpgContext.cpp index 72c04ac9..ff32edd8 100644 --- a/src/gpg/GpgContext.cpp +++ b/src/gpg/GpgContext.cpp @@ -694,13 +694,12 @@ namespace GpgME { } gpg_error_t - GpgContext::sign(const QVector<GpgKey> &keys, const QByteArray &inBuffer, QByteArray *outBuffer, bool detached, + GpgContext::sign(const QVector<GpgKey> &keys, const QByteArray &inBuffer, QByteArray *outBuffer, gpgme_sig_mode_t mode, gpgme_sign_result_t *result) { gpgme_error_t gpgmeError; gpgme_data_t dataIn, dataOut; gpgme_sign_result_t m_result; - gpgme_sig_mode_t mode; if (keys.isEmpty()) { QMessageBox::critical(nullptr, tr("Key Selection"), tr("No Private Key Selected")); @@ -729,12 +728,6 @@ namespace GpgME { mode settings of the context are ignored. */ - if (detached) { - mode = GPGME_SIG_MODE_DETACH; - } else { - mode = GPGME_SIG_MODE_CLEAR; - } - gpgmeError = gpgme_op_sign(mCtx, dataIn, dataOut, mode); checkErr(gpgmeError); diff --git a/src/gpg/GpgFileOpera.cpp b/src/gpg/GpgFileOpera.cpp index 9395bd17..5d924349 100644 --- a/src/gpg/GpgFileOpera.cpp +++ b/src/gpg/GpgFileOpera.cpp @@ -114,7 +114,7 @@ gpgme_error_t GpgFileOpera::signFile(GpgME::GpgContext *ctx, QVector<GpgKey> &ke auto outBuffer = QByteArray(); infile.close(); - auto error = ctx->sign(keys, inBuffer, &outBuffer, true, result); + auto error = ctx->sign(keys, inBuffer, &outBuffer, GPGME_SIG_MODE_DETACH, result); if (gpg_err_code(error) != GPG_ERR_NO_ERROR) return error; diff --git a/src/gpg/GpgUID.cpp b/src/gpg/GpgUID.cpp index f8f7e8fa..0dc6abfd 100644 --- a/src/gpg/GpgUID.cpp +++ b/src/gpg/GpgUID.cpp @@ -1,6 +1,26 @@ -// -// Created by eric on 2021/5/22. -// +/** + * 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. + * + * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ #include "gpg/GpgUID.h" diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt new file mode 100644 index 00000000..867be076 --- /dev/null +++ b/src/server/CMakeLists.txt @@ -0,0 +1,6 @@ +aux_source_directory(. SERVER_SOURCE) + +add_library(server STATIC ${SERVER_SOURCE}) + +target_link_libraries(server + Qt5::Network Qt5::Widgets Qt5::Core) diff --git a/src/server/ComUtils.cpp b/src/server/ComUtils.cpp new file mode 100644 index 00000000..637b5c12 --- /dev/null +++ b/src/server/ComUtils.cpp @@ -0,0 +1,81 @@ +/** + * 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. + * + * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "server/ComUtils.h" + +/** + * check server reply if it can parse into a json object + * @param reply reply data in byte array + * @return if successful + */ +bool ComUtils::checkServerReply(const QByteArray &reply) { + + /** + * Server Reply Format(Except Timeout) + * { + * "status": 200, + * "message": "OK", + * "data" : { + * ... + * } + * } + */ + + // check if reply is a json object + if (replyDoc.Parse(reply).HasParseError() || !replyDoc.IsObject()) { + QMessageBox::critical(this, tr("Error"), tr("Unknown Error")); + return false; + } + + // check status(int) and message(string) + if (replyDoc.HasMember("status") && replyDoc.HasMember("message") + && replyDoc["status"].IsInt() && replyDoc["message"].IsString()) { + + int status = replyDoc["status"].GetInt(); + QString message = replyDoc["status"].GetString(); + + // check status code if successful (200-299) + // check data object + if (status / 10 == 2 && replyDoc.HasMember("data") && replyDoc["data"].IsObject()) { + dataVal = replyDoc["data"].GetObjectA(); + is_good = true; + return true; + } else QMessageBox::critical(this, tr("Error"), message); + + } else QMessageBox::critical(this, tr("Error"), tr("Unknown Reply Format")); +} + +/** + * get value in data + * @param key key of value + * @return value in string format + */ +QString ComUtils::getDataValue(const QString &key) { + if (is_good) { + auto k_byte_array = key.toUtf8(); + if (dataVal.HasMember(k_byte_array.data())) { + return dataVal[k_byte_array.data()].GetString(); + } else return {}; + } else return {}; +} diff --git a/src/ui/FileEncryptionDialog.cpp b/src/ui/FileEncryptionDialog.cpp index e92dfc90..d9bc7ce2 100755 --- a/src/ui/FileEncryptionDialog.cpp +++ b/src/ui/FileEncryptionDialog.cpp @@ -229,7 +229,7 @@ void FileEncryptionDialog::slotExecuteAction() { if (mAction == Sign) { qDebug() << "Action Sign"; - gpgme_error_t err = mCtx->sign(keys, inBuffer, outBuffer, true); + gpgme_error_t err = mCtx->sign(keys, inBuffer, outBuffer, GPGME_SIG_MODE_DETACH); if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) { qDebug() << "Error" << gpgme_strerror(err); QMessageBox::warning(this, tr("Error"), diff --git a/src/ui/KeyUploadDialog.cpp b/src/ui/KeyUploadDialog.cpp index faf892f0..ab38569f 100644 --- a/src/ui/KeyUploadDialog.cpp +++ b/src/ui/KeyUploadDialog.cpp @@ -24,8 +24,6 @@ #include "ui/KeyUploadDialog.h" -#include <utility> - KeyUploadDialog::KeyUploadDialog(GpgME::GpgContext *ctx, const QVector<GpgKey> &keys, QWidget *parent) : appPath(qApp->applicationDirPath()), settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat), diff --git a/src/ui/SettingsDialog.cpp b/src/ui/SettingsDialog.cpp index 1732d718..00b26e7b 100755 --- a/src/ui/SettingsDialog.cpp +++ b/src/ui/SettingsDialog.cpp @@ -26,6 +26,9 @@ #include "smtp/SmtpMime" #include "ui/WaitingDialog.h" +#include "rapidjson/document.h" +#include "rapidjson/prettywriter.h" + SettingsDialog::SettingsDialog(GpgME::GpgContext *ctx, QWidget *parent) : QDialog(parent) { mCtx = ctx; @@ -132,14 +135,15 @@ GeneralTab::GeneralTab(GpgME::GpgContext *ctx, QWidget *parent) mCtx = ctx; /***************************************** - * remember Password-Box + * GpgFrontend Server *****************************************/ - auto *rememberPasswordBox = new QGroupBox(tr("Remember Password")); - auto *rememberPasswordBoxLayout = new QHBoxLayout(); - rememberPasswordCheckBox = - new QCheckBox(tr("Remember password until closing gpg4usb"), this); - rememberPasswordBoxLayout->addWidget(rememberPasswordCheckBox); - rememberPasswordBox->setLayout(rememberPasswordBoxLayout); + auto *serverBox = new QGroupBox(tr("GpgFrontend Server")); + auto *serverBoxLayout = new QVBoxLayout(); + serverSelectBox = new QComboBox(); + serverBoxLayout->addWidget(serverSelectBox); + serverBoxLayout->addWidget(new QLabel( + tr("Server that provides short key and key exchange services"))); + serverBox->setLayout(serverBoxLayout); /***************************************** * Save-Checked-Keys-Box @@ -171,7 +175,7 @@ GeneralTab::GeneralTab(GpgME::GpgContext *ctx, QWidget *parent) langSelectBox = new QComboBox; lang = SettingsDialog::listLanguages(); - foreach (QString l, lang) { langSelectBox->addItem(l); } + for (const auto &l: lang) { langSelectBox->addItem(l); } langBoxLayout->addWidget(langSelectBox); langBoxLayout->addWidget( @@ -186,7 +190,10 @@ GeneralTab::GeneralTab(GpgME::GpgContext *ctx, QWidget *parent) *****************************************/ auto *ownKeyBox = new QGroupBox(tr("Own key")); auto *ownKeyBoxLayout = new QVBoxLayout(); + auto *ownKeyServiceTokenLayout = new QHBoxLayout(); ownKeySelectBox = new QComboBox; + getServiceTokenButton = new QPushButton(tr("Get Service Token")); + serviceTokenLabel = new QLabel(tr("No Service Token Found")); ownKeyBox->setLayout(ownKeyBoxLayout); mKeyList = new KeyList(mCtx); @@ -204,16 +211,22 @@ GeneralTab::GeneralTab(GpgME::GpgContext *ctx, QWidget *parent) } connect(ownKeySelectBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotOwnKeyIdChanged())); + connect(getServiceTokenButton, SIGNAL(clicked(bool)), this, + SLOT(slotGetServiceToken())); ownKeyBoxLayout->addWidget(new QLabel( tr("Key pair for synchronization and identity authentication"))); ownKeyBoxLayout->addWidget(ownKeySelectBox); + ownKeyBoxLayout->addLayout(ownKeyServiceTokenLayout); + ownKeyServiceTokenLayout->addWidget(getServiceTokenButton); + ownKeyServiceTokenLayout->addWidget(serviceTokenLabel); + ownKeyServiceTokenLayout->stretch(0); /***************************************** * Mainlayout *****************************************/ auto *mainLayout = new QVBoxLayout; - mainLayout->addWidget(rememberPasswordBox); + mainLayout->addWidget(serverBox); mainLayout->addWidget(saveCheckedKeysBox); mainLayout->addWidget(importConfirmationBox); mainLayout->addWidget(langBox); @@ -235,6 +248,15 @@ void GeneralTab::setSettings() { saveCheckedKeysCheckBox->setCheckState(Qt::Checked); } + auto serverList = settings.value("general/gpgfrontendServerList").toStringList(); + if(serverList.empty()) { + serverList.append("service.gpgfrontend.pub"); + } + for(const auto &s : serverList) + serverSelectBox->addItem(s); + serverSelectBox->setCurrentText(settings.value("general/currentGpgfrontendServer", + "service.gpgfrontend.pub").toString()); + // Language setting QString langKey = settings.value("int/lang").toString(); QString langValue = lang.value(langKey); @@ -242,16 +264,22 @@ void GeneralTab::setSettings() { langSelectBox->setCurrentIndex(langSelectBox->findText(langValue)); } - QString ownKeyId = settings.value("general/ownKeyId").toString(); - qDebug() << "OwnKeyId" << ownKeyId; - if (ownKeyId.isEmpty()) { + QString own_key_id = settings.value("general/ownKeyId").toString(); + qDebug() << "OwnKeyId" << own_key_id; + if (own_key_id.isEmpty()) { ownKeySelectBox->setCurrentText("<none>"); } else { - const auto text = keyIds.find(ownKeyId).value(); - qDebug() << "OwnKey" << ownKeyId << text; + const auto text = keyIds.find(own_key_id).value(); + qDebug() << "OwnKey" << own_key_id << text; ownKeySelectBox->setCurrentText(text); } + serviceToken = settings.value("general/serviceToken").toString(); + qDebug() << "Load Service Token" << serviceToken; + if(!serviceToken.isEmpty()) { + serviceTokenLabel->setText(serviceToken); + } + // Get own key information from keydb/gpg.conf (if contained) if (settings.value("general/confirmImportKeys", Qt::Checked).toBool()) { importConfirmationCheckBox->setCheckState(Qt::Checked); @@ -265,12 +293,25 @@ void GeneralTab::setSettings() { void GeneralTab::applySettings() { settings.setValue("keys/saveKeyChecked", saveCheckedKeysCheckBox->isChecked()); - // TODO: clear passwordCache instantly on unset rememberPassword - settings.setValue("general/rememberPassword", - rememberPasswordCheckBox->isChecked()); + + settings.setValue("general/currentGpgfrontendServer", + serverSelectBox->currentText()); + + auto *serverList = new QStringList(); + for(int i = 0; i < serverSelectBox->count(); i++) + serverList->append(serverSelectBox->itemText(i)); + settings.setValue("general/gpgfrontendServerList", + *serverList); + delete serverList; + settings.setValue("int/lang", lang.key(langSelectBox->currentText())); + settings.setValue("general/ownKeyId", keyIdsList[ownKeySelectBox->currentIndex()]); + + settings.setValue("general/serviceToken", + serviceToken); + settings.setValue("general/confirmImportKeys", importConfirmationCheckBox->isChecked()); } @@ -279,6 +320,81 @@ void GeneralTab::slotLanguageChanged() { emit signalRestartNeeded(true); } void GeneralTab::slotOwnKeyIdChanged() { // Set ownKeyId to currently selected + this->serviceTokenLabel->setText(tr("No Service Token Found")); + serviceToken.clear(); +} + +void GeneralTab::slotGetServiceToken() { + QUrl reqUrl("http://127.0.0.1:9048/user"); + QNetworkRequest request(reqUrl); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + + // Building Post Data + QByteArray keyDataBuf; + + const auto keyId = keyIdsList[ownKeySelectBox->currentIndex()]; + + qDebug() << "KeyId" << keyIdsList[ownKeySelectBox->currentIndex()]; + + if(keyId.isEmpty()) { + QMessageBox::critical(this, tr("Invalid Operation"), tr("Own Key can not be None while getting service token.")); + return; + } + + QStringList selectedKeyIds(keyIdsList[ownKeySelectBox->currentIndex()]); + mCtx->exportKeys(&selectedKeyIds, &keyDataBuf); + + qDebug() << "keyDataBuf" << keyDataBuf; + + rapidjson::Value p, v; + + rapidjson::Document doc; + doc.SetObject(); + + p.SetString(keyDataBuf.constData(), keyDataBuf.count()); + + auto version = qApp->applicationVersion(); + v.SetString(version.toUtf8().constData(), qApp->applicationVersion().count()); + + doc.AddMember("publicKey", p, doc.GetAllocator()); + doc.AddMember("version", v, doc.GetAllocator()); + + rapidjson::StringBuffer sb; + rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(sb); + doc.Accept(writer); + + QByteArray postData(sb.GetString()); + + QNetworkReply *reply = manager.post(request, postData); + + auto dialog = new WaitingDialog("Getting Token From Server", this); + dialog->show(); + + while (reply->isRunning()) { + QApplication::processEvents(); + } + + dialog->close(); + + if(reply->error() == QNetworkReply::NoError) { + rapidjson::Document docReply; + docReply.Parse(reply->readAll().constData()); + QString serviceTokenTemp = docReply["serviceToken"].GetString(); + if(checkUUIDFormat(serviceTokenTemp)) { + serviceToken = serviceTokenTemp; + qDebug() << "Get Service Token" << serviceToken; + serviceTokenLabel->setText(serviceToken); + } else { + QMessageBox::critical(this, tr("Error"), tr("Invalid Service Token Format")); + } + } else { + QMessageBox::critical(this, tr("Error"), reply->errorString()); + } + +} + +bool GeneralTab::checkUUIDFormat(const QString& uuid) { + return re_uuid.match(uuid).hasMatch(); } SendMailTab::SendMailTab(QWidget *parent) @@ -304,7 +420,7 @@ SendMailTab::SendMailTab(QWidget *parent) connectionTypeComboBox->addItem("STARTTLS"); defaultSender = new QLineEdit();; - checkConnectionButton = new QPushButton("Check Connection"); + checkConnectionButton = new QPushButton(tr("Check Connection")); auto layout = new QGridLayout(); layout->addWidget(enableCheckBox, 0, 0); @@ -378,13 +494,11 @@ void SendMailTab::applySettings() { void SendMailTab::slotCheckConnection() { - SmtpClient::ConnectionType connectionType = SmtpClient::ConnectionType::TcpConnection; - - if (connectionTypeComboBox->currentText() == "SSL") { + SmtpClient::ConnectionType connectionType; + const auto selectedConnType = connectionTypeComboBox->currentText(); + if (selectedConnType == "SSL") { connectionType = SmtpClient::ConnectionType::SslConnection; - } else if (connectionTypeComboBox->currentText() == "TLS") { - connectionType = SmtpClient::ConnectionType::TlsConnection; - } else if (connectionTypeComboBox->currentText() == "STARTTLS") { + } else if (selectedConnType == "TLS" || selectedConnType == "STARTTLS") { connectionType = SmtpClient::ConnectionType::TlsConnection; } else { connectionType = SmtpClient::ConnectionType::TcpConnection; @@ -392,9 +506,6 @@ void SendMailTab::slotCheckConnection() { SmtpClient smtp(smtpAddress->text(), portSpin->value(), connectionType); - // We need to set the username (your email address) and the password - // for smtp authentification. - smtp.setUser(username->text()); smtp.setPassword(password->text()); @@ -648,6 +759,7 @@ void KeyserverTab::setSettings() { qDebug() << "KeyserverTab ListItemText" << comboBox->itemText(i); } settings.setValue("keyserver/keyServerList", *keyServerList); + delete keyServerList; settings.setValue("keyserver/defaultKeyServer", comboBox->currentText()); } diff --git a/src/ui/ShowCopyDialog.cpp b/src/ui/ShowCopyDialog.cpp new file mode 100644 index 00000000..58a6cf0a --- /dev/null +++ b/src/ui/ShowCopyDialog.cpp @@ -0,0 +1,26 @@ +// +// Created by Administrator on 2021/7/21. +// + +#include "ui/ShowCopyDialog.h" + +ShowCopyDialog::ShowCopyDialog(const QString &text, QWidget *parent) : QDialog(parent) { + textEdit = new QTextEdit(); + textEdit->setReadOnly(true); + textEdit->setLineWrapMode(QTextEdit::WidgetWidth); + textEdit->setText(text); + copyButton = new QPushButton("Copy"); + connect(copyButton, SIGNAL(clicked(bool)), this, SLOT(slotCopyText())); + + auto *layout = new QVBoxLayout(); + layout->addWidget(textEdit); + layout->addWidget(copyButton); + + this->setModal(true); + this->setLayout(layout); +} + +void ShowCopyDialog::slotCopyText() { + QClipboard *cb = QApplication::clipboard(); + cb->setText(textEdit->toPlainText()); +} diff --git a/src/ui/main_window/MainWindowSlotFunction.cpp b/src/ui/main_window/MainWindowSlotFunction.cpp index 4bcee080..736fecb5 100644 --- a/src/ui/main_window/MainWindowSlotFunction.cpp +++ b/src/ui/main_window/MainWindowSlotFunction.cpp @@ -23,7 +23,12 @@ */ #include "MainWindow.h" +#include "server/ComUtils.h" #include "ui/SendMailDialog.h" +#include "ui/ShowCopyDialog.h" + +#include "rapidjson/document.h" +#include "rapidjson/prettywriter.h" void MainWindow::slotEncrypt() { @@ -77,6 +82,7 @@ void MainWindow::slotEncrypt() { edit->slotFillTextEditWithText(*tmp2); infoBoard->associateTextEdit(edit->curTextPage()); + // check result analyse status if (resultAnalyse->getStatus() < 0) infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL); else if (resultAnalyse->getStatus() > 0) @@ -84,10 +90,11 @@ void MainWindow::slotEncrypt() { else infoBoard->slotRefresh(reportText, INFO_ERROR_WARN); + // set optional actions if (resultAnalyse->getStatus() >= 0) { infoBoard->resetOptionActionsMenu(); infoBoard->addOptionalAction("Send Mail", [this]() { - if(settings.value("sendMail/enable", false).toBool()) + if (settings.value("sendMail/enable", false).toBool()) new SendMailDialog(edit->curTextPage()->toPlainText(), this); else { QMessageBox::warning(nullptr, @@ -134,7 +141,7 @@ void MainWindow::slotSign() { gpgme_error_t error; auto thread = QThread::create([&]() { - error = mCtx->sign(keys, edit->curTextPage()->toPlainText().toUtf8(), tmp, false, &result); + error = mCtx->sign(keys, edit->curTextPage()->toPlainText().toUtf8(), tmp, GPGME_SIG_MODE_CLEAR, &result); }); connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater())); thread->start(); @@ -361,7 +368,7 @@ void MainWindow::slotEncryptSign() { if (status >= 0) { infoBoard->resetOptionActionsMenu(); infoBoard->addOptionalAction("Send Mail", [this]() { - if(settings.value("sendMail/enable", false).toBool()) + if (settings.value("sendMail/enable", false).toBool()) new SendMailDialog(edit->curTextPage()->toPlainText(), this); else { QMessageBox::warning(nullptr, @@ -369,6 +376,15 @@ void MainWindow::slotEncryptSign() { tr("Please go to the settings interface to enable and configure this function.")); } }); + infoBoard->addOptionalAction("Shorten Crypt Text", [this]() { + if (settings.value("general/serviceToken").toString().isEmpty()) + QMessageBox::warning(nullptr, + tr("Service Token Empty"), + tr("Please go to the settings interface to set Own Key and get Service Token.")); + else { + shortenCryptText(); + } + }); } delete resultAnalyseEncr; @@ -385,7 +401,18 @@ void MainWindow::slotDecryptVerify() { if (edit->slotCurPageTextEdit() != nullptr) { auto *decrypted = new QByteArray(); - QByteArray text = edit->curTextPage()->toPlainText().toUtf8(); + QString plainText = edit->curTextPage()->toPlainText(); + + + if (plainText.trimmed().startsWith("[GpgFrontend_ShortCrypto]://")) { + auto cryptoText = getCryptText(plainText); + if (!cryptoText.isEmpty()) { + plainText = cryptoText; + } + } + + QByteArray text = plainText.toUtf8(); + GpgME::GpgContext::preventNoDataErr(&text); gpgme_decrypt_result_t d_result = nullptr; @@ -435,6 +462,160 @@ void MainWindow::slotDecryptVerify() { } } +/** + * get full size crypt text from server using short crypto text + * @param shortenCryptoText short crypto text([GpgFrontend_ShortCrypto]://) + * @return + */ +QString MainWindow::getCryptText(const QString &shortenCryptoText) { + QString host = settings.value("general/currentGpgfrontendServer", + "service.gpgfrontend.pub").toString(); + + QString ownKeyId = settings.value("general/ownKeyId").toString(); + + GpgKey key = mCtx->getKeyById(ownKeyId); + if (!key.good) { + QMessageBox::critical(this, tr("Invalid Own Key"), tr("Own Key can not be use to do any operation.")); + return {}; + } + + QString serviceToken = settings.value("general/serviceToken").toString(); + if (serviceToken.isEmpty()) { + QMessageBox::critical(this, tr("Error"), + tr("Please obtain a Service Token from the server in the settings.")); + return {}; + } + + QUrl reqUrl("http://127.0.0.1:9048/text/get"); + QNetworkRequest request(reqUrl); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + + // Sign Shorten Text + QVector keys{key}; + QByteArray outSignText; + mCtx->sign(keys, shortenCryptoText.toUtf8(), &outSignText, GPGME_SIG_MODE_NORMAL); + auto outSignTextBase64 = outSignText.toBase64(); + + rapidjson::Document doc; + doc.SetObject(); + + rapidjson::Value s, t; + + // Signature + s.SetString(outSignTextBase64.constData(), outSignTextBase64.count()); + // Service Token + const auto t_byte_array = serviceToken.toUtf8(); + t.SetString(t_byte_array.constData(), t_byte_array.count()); + + doc.AddMember("signature", s, doc.GetAllocator()); + doc.AddMember("serviceToken", t, doc.GetAllocator()); + + rapidjson::StringBuffer sb; + rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(sb); + doc.Accept(writer); + + QByteArray postData(sb.GetString()); + qDebug() << "postData" << QString::fromUtf8(postData); + + QNetworkReply *reply = networkAccessManager->post(request, postData); + + auto dialog = new WaitingDialog("Getting Crypt Text From Server", this); + dialog->show(); + + while (reply->isRunning()) { + QApplication::processEvents(); + } + + dialog->close(); + + QByteArray replyData = reply->readAll().constData(); + auto comUtils = new ComUtils(this); + if (comUtils->checkServerReply(replyData)) { + //TODO Logic + } else QMessageBox::critical(this, tr("Error"), tr("Unknown Error")); + + return {}; +} + +void MainWindow::shortenCryptText() { + + QString serviceToken = settings.value("general/serviceToken").toString(); + QString ownKeyId = settings.value("general/ownKeyId").toString(); + + QByteArray cryptoText = edit->curTextPage()->toPlainText().toUtf8(); + + QUrl reqUrl("http://127.0.0.1:9048/text/new"); + QNetworkRequest request(reqUrl); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + + GpgKey key = mCtx->getKeyById(ownKeyId); + if (!key.good) { + QMessageBox::critical(this, tr("Invalid Own Key"), tr("Own Key can not be use to do any operation.")); + return; + } + + QCryptographicHash ch(QCryptographicHash::Md5); + ch.addData(cryptoText); + QString md5 = ch.result().toHex(); + + qDebug() << "md5" << md5; + + QByteArray signText = QString("[%1][%2]").arg(serviceToken, md5).toUtf8(); + + QCryptographicHash sha(QCryptographicHash::Sha256); + sha.addData(signText); + QString shaText = sha.result().toHex(); + + qDebug() << "shaText" << shaText; + + QVector keys{key}; + QByteArray outSignText; + mCtx->sign(keys, signText, &outSignText, GPGME_SIG_MODE_NORMAL); + QByteArray outSignTextBase64 = outSignText.toBase64(); + + rapidjson::Value c, s, m, t; + + rapidjson::Document doc; + doc.SetObject(); + + c.SetString(cryptoText.constData(), cryptoText.count()); + auto m_byte_array = shaText.toUtf8(); + m.SetString(m_byte_array.constData(), m_byte_array.count()); + s.SetString(outSignTextBase64.constData(), outSignTextBase64.count()); + auto t_byte_array = serviceToken.toUtf8(); + t.SetString(t_byte_array.constData(), t_byte_array.count()); + + doc.AddMember("cryptoText", c, doc.GetAllocator()); + doc.AddMember("sha", m, doc.GetAllocator()); + doc.AddMember("sign", s, doc.GetAllocator()); + doc.AddMember("serviceToken", t, doc.GetAllocator()); + + rapidjson::StringBuffer sb; + rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(sb); + doc.Accept(writer); + + QByteArray postData(sb.GetString()); + qDebug() << "postData" << QString::fromUtf8(postData); + + QNetworkReply *reply = networkAccessManager->post(request, postData); + + while (reply->isRunning()) { + QApplication::processEvents(); + } + + if (reply->error() == QNetworkReply::NoError) { + rapidjson::Document docReply; + docReply.Parse(reply->readAll().constData()); + QString shortenText = docReply["shortenText"].GetString(); + auto *dialog = new ShowCopyDialog(shortenText, this); + dialog->show(); + } else { + QMessageBox::critical(this, tr("Error"), reply->errorString()); + } + + +} + /* * Append the selected (not checked!) Key(s) To Textedit */ @@ -1077,14 +1258,14 @@ void MainWindow::slotOpenFile(QString &path) { } void MainWindow::slotVersionUpgrade(const QString ¤tVersion, const QString &latestVersion) { - if(currentVersion < latestVersion) { + if (currentVersion < latestVersion) { QMessageBox::warning(this, tr("Outdated Version"), tr("This version(%1) is out of date, please update the latest version in time. ").arg( currentVersion) + tr("You can download the latest version(%1) on Github Releases Page.<br/>").arg( latestVersion)); - } else if(currentVersion > latestVersion) { + } else if (currentVersion > latestVersion) { QMessageBox::warning(this, tr("Unreleased Version"), tr("This version(%1) has not been officially released and is not recommended for use in a production environment. <br/>").arg( diff --git a/src/ui/widgets/EditorPage.cpp b/src/ui/widgets/EditorPage.cpp index 05d5cbea..beb37b96 100644 --- a/src/ui/widgets/EditorPage.cpp +++ b/src/ui/widgets/EditorPage.cpp @@ -44,8 +44,6 @@ EditorPage::EditorPage(QString filePath, QWidget *parent) : QWidget(parent), // Front in same width this->setFont({"Courier"}); - - connect(textPage, SIGNAL(textChanged()), this, SLOT(formatGpgHeader())); } const QString &EditorPage::getFilePath() const { diff --git a/src/ui/widgets/InfoBoardWidget.cpp b/src/ui/widgets/InfoBoardWidget.cpp index f26917a4..f64fda49 100644 --- a/src/ui/widgets/InfoBoardWidget.cpp +++ b/src/ui/widgets/InfoBoardWidget.cpp @@ -150,9 +150,12 @@ void InfoBoardWidget::associateTabWidget(QTabWidget *tab) { connect(tab, SIGNAL(tabCloseRequested(int)), this, SLOT(slotReset())); } + void InfoBoardWidget::addOptionalAction(const QString &name, const std::function<void()> &action) { auto actionButton = new QPushButton(name); infoBoard->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + // set margin from surroundings + actionButton->setContentsMargins(5, 5, 5, 5); actionButtonLayout->addWidget(actionButton); connect(actionButton, &QPushButton::clicked, this, [=]() { action(); diff --git a/src/ui/widgets/KeyList.cpp b/src/ui/widgets/KeyList.cpp index 3929868e..25f8870e 100644 --- a/src/ui/widgets/KeyList.cpp +++ b/src/ui/widgets/KeyList.cpp @@ -31,8 +31,7 @@ KeyList::KeyList(GpgME::GpgContext *ctx, KeyListColumn::InfoType infoType, QWidget *parent) : QWidget(parent), mSelectType(selectType), mInfoType(infoType), appPath(qApp->applicationDirPath()), - settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat) -{ + settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat) { mCtx = ctx; @@ -43,7 +42,7 @@ KeyList::KeyList(GpgME::GpgContext *ctx, mKeyList->setShowGrid(false); mKeyList->sortByColumn(2, Qt::AscendingOrder); mKeyList->setSelectionBehavior(QAbstractItemView::SelectRows); - mKeyList->setSelectionMode( QAbstractItemView::SingleSelection ); + mKeyList->setSelectionMode(QAbstractItemView::SingleSelection); // tableitems not editable mKeyList->setEditTriggers(QAbstractItemView::NoEditTriggers); @@ -54,22 +53,22 @@ KeyList::KeyList(GpgME::GpgContext *ctx, mKeyList->setAlternatingRowColors(true); // Hidden Column For Purpose - if(!(mInfoType & KeyListColumn::TYPE)) { + if (!(mInfoType & KeyListColumn::TYPE)) { mKeyList->setColumnHidden(1, true); } - if(!(mInfoType & KeyListColumn::NAME)) { + if (!(mInfoType & KeyListColumn::NAME)) { mKeyList->setColumnHidden(2, true); } - if(!(mInfoType & KeyListColumn::EmailAddress)) { + if (!(mInfoType & KeyListColumn::EmailAddress)) { mKeyList->setColumnHidden(3, true); } - if(!(mInfoType & KeyListColumn::Usage)) { + if (!(mInfoType & KeyListColumn::Usage)) { mKeyList->setColumnHidden(4, true); } - if(!(mInfoType & KeyListColumn::Validity)) { + if (!(mInfoType & KeyListColumn::Validity)) { mKeyList->setColumnHidden(5, true); } - if(!(mInfoType & KeyListColumn::FingerPrint)) { + if (!(mInfoType & KeyListColumn::FingerPrint)) { mKeyList->setColumnHidden(6, true); } @@ -95,8 +94,7 @@ KeyList::KeyList(GpgME::GpgContext *ctx, slotRefresh(); } -void KeyList::slotRefresh() -{ +void KeyList::slotRefresh() { QStringList *keyList; keyList = getChecked(); // while filling the table, sort enabled causes errors @@ -110,21 +108,21 @@ void KeyList::slotRefresh() int row_count = 0; while (it != keys.end()) { - if(mFilter != nullptr) { - if(!mFilter(*it)) { + if (mFilter != nullptr) { + if (!mFilter(*it)) { it = keys.erase(it); continue; } } - if(!excluded_key_ids.isEmpty()){ + if (!excluded_key_ids.isEmpty()) { auto iterator = std::find_if(excluded_key_ids.begin(), excluded_key_ids.end(), - [it] (const auto &key_id) -> bool { - if(it->id == key_id) return true; - else return false; - }); + [it](const auto &key_id) -> bool { + if (it->id == key_id) return true; + else return false; + }); - if(iterator != excluded_key_ids.end()) { + if (iterator != excluded_key_ids.end()) { it = keys.erase(it); continue; } @@ -161,10 +159,10 @@ void KeyList::slotRefresh() type_steam << "pub"; } - if(it->is_private_key && !it->has_master_key) { + if (it->is_private_key && !it->has_master_key) { type_steam << "#"; } - auto* tmp1 = new QTableWidgetItem(type_str); + auto *tmp1 = new QTableWidgetItem(type_str); mKeyList->setItem(row_index, 1, tmp1); auto *tmp2 = new QTableWidgetItem(it->name); @@ -177,13 +175,13 @@ void KeyList::slotRefresh() QString usage; QTextStream usage_steam(&usage); - if(GpgME::GpgContext::checkIfKeyCanCert(*it)) + if (GpgME::GpgContext::checkIfKeyCanCert(*it)) usage_steam << "C"; - if(GpgME::GpgContext::checkIfKeyCanEncr(*it)) + if (GpgME::GpgContext::checkIfKeyCanEncr(*it)) usage_steam << "E"; - if(GpgME::GpgContext::checkIfKeyCanSign(*it)) + if (GpgME::GpgContext::checkIfKeyCanSign(*it)) usage_steam << "S"; - if(GpgME::GpgContext::checkIfKeyCanAuth(*it)) + if (GpgME::GpgContext::checkIfKeyCanAuth(*it)) usage_steam << "A"; auto *temp_usage = new QTableWidgetItem(usage); @@ -199,7 +197,7 @@ void KeyList::slotRefresh() mKeyList->setItem(row_index, 6, temp_fpr); // strike out expired keys - if(it->expired || it->revoked) { + if (it->expired || it->revoked) { QFont strike = tmp2->font(); strike.setStrikeOut(true); tmp0->setFont(strike); @@ -218,8 +216,7 @@ void KeyList::slotRefresh() setChecked(keyList); } -QStringList *KeyList::getChecked() -{ +QStringList *KeyList::getChecked() { auto *ret = new QStringList(); for (int i = 0; i < mKeyList->rowCount(); i++) { if (mKeyList->item(i, 0)->checkState() == Qt::Checked) { @@ -229,19 +226,17 @@ QStringList *KeyList::getChecked() return ret; } -QStringList *KeyList::getAllPrivateKeys() -{ +QStringList *KeyList::getAllPrivateKeys() { auto *ret = new QStringList(); for (int i = 0; i < mKeyList->rowCount(); i++) { - if (mKeyList->item(i, 1)) { + if (mKeyList->item(i, 1) && buffered_keys[i].is_private_key) { *ret << buffered_keys[i].id; } } return ret; } -QStringList *KeyList::getPrivateChecked() -{ +QStringList *KeyList::getPrivateChecked() { auto *ret = new QStringList(); for (int i = 0; i < mKeyList->rowCount(); i++) { if ((mKeyList->item(i, 0)->checkState() == Qt::Checked) && (mKeyList->item(i, 1))) { @@ -251,19 +246,17 @@ QStringList *KeyList::getPrivateChecked() return ret; } -void KeyList::setChecked(QStringList *keyIds) -{ +void KeyList::setChecked(QStringList *keyIds) { if (!keyIds->isEmpty()) { for (int i = 0; i < mKeyList->rowCount(); i++) { - if (keyIds->contains(buffered_keys[i].id)) { + if (keyIds->contains(buffered_keys[i].id)) { mKeyList->item(i, 0)->setCheckState(Qt::Checked); } } } } -QStringList *KeyList::getSelected() -{ +QStringList *KeyList::getSelected() { auto *ret = new QStringList(); for (int i = 0; i < mKeyList->rowCount(); i++) { @@ -274,47 +267,42 @@ QStringList *KeyList::getSelected() return ret; } -[[maybe_unused]] bool KeyList::containsPrivateKeys() -{ +[[maybe_unused]] bool KeyList::containsPrivateKeys() { for (int i = 0; i < mKeyList->rowCount(); i++) { if (mKeyList->item(i, 1)) { - return true; + return true; } } return false; } -void KeyList::setColumnWidth(int row, int size) -{ +void KeyList::setColumnWidth(int row, int size) { mKeyList->setColumnWidth(row, size); } -void KeyList::contextMenuEvent(QContextMenuEvent *event) -{ +void KeyList::contextMenuEvent(QContextMenuEvent *event) { if (mKeyList->selectedItems().length() > 0) { popupMenu->exec(event->globalPos()); } } -void KeyList::addSeparator() -{ +void KeyList::addSeparator() { popupMenu->addSeparator(); } -void KeyList::addMenuAction(QAction *act) -{ +void KeyList::addMenuAction(QAction *act) { popupMenu->addAction(act); } -void KeyList::dropEvent(QDropEvent* event) -{ +void KeyList::dropEvent(QDropEvent *event) { auto *dialog = new QDialog(); dialog->setWindowTitle(tr("Import Keys")); QLabel *label; - label = new QLabel(tr("You've dropped something on the table.\n GpgFrontend will now try to import key(s).")+"\n"); + label = new QLabel( + tr("You've dropped something on the table.\n GpgFrontend will now try to import key(s).") + "\n"); // "always import keys"-CheckBox auto *checkBox = new QCheckBox(tr("Always import without bothering.")); @@ -332,56 +320,50 @@ void KeyList::dropEvent(QDropEvent* event) dialog->setLayout(vbox); - if (settings.value("general/confirmImportKeys",Qt::Checked).toBool()) - { + if (settings.value("general/confirmImportKeys", Qt::Checked).toBool()) { dialog->exec(); if (dialog->result() == QDialog::Rejected) { return; } - if (checkBox->isChecked()){ - settings.setValue("general/confirmImportKeys", false); + if (checkBox->isChecked()) { + settings.setValue("general/confirmImportKeys", false); } else { settings.setValue("general/confirmImportKeys", true); } } - if (event->mimeData()->hasUrls()) - { - for (const QUrl& tmp : event->mimeData()->urls()) - { - QFile file; - file.setFileName(tmp.toLocalFile()); - if (!file.open(QIODevice::ReadOnly)) { - qDebug() << tr("Couldn't Open File: ") + tmp.toString(); - } - QByteArray inBuffer = file.readAll(); - this->importKeys(inBuffer); - file.close(); - } - } else { - QByteArray inBuffer(event->mimeData()->text().toUtf8()); + if (event->mimeData()->hasUrls()) { + for (const QUrl &tmp : event->mimeData()->urls()) { + QFile file; + file.setFileName(tmp.toLocalFile()); + if (!file.open(QIODevice::ReadOnly)) { + qDebug() << tr("Couldn't Open File: ") + tmp.toString(); + } + QByteArray inBuffer = file.readAll(); this->importKeys(inBuffer); - } + file.close(); + } + } else { + QByteArray inBuffer(event->mimeData()->text().toUtf8()); + this->importKeys(inBuffer); + } } -void KeyList::dragEnterEvent(QDragEnterEvent *event) -{ +void KeyList::dragEnterEvent(QDragEnterEvent *event) { event->acceptProposedAction(); } /** set background color for Keys and put them to top * */ -[[maybe_unused]] void KeyList::markKeys(QStringList *keyIds) -{ - foreach(QString id, *keyIds) { - qDebug() << "marked: " << id; - } +[[maybe_unused]] void KeyList::markKeys(QStringList *keyIds) { + foreach(QString id, *keyIds) { + qDebug() << "marked: " << id; + } } -void KeyList::importKeys(QByteArray inBuffer) -{ +void KeyList::importKeys(QByteArray inBuffer) { GpgImportInformation result = mCtx->importKey(std::move(inBuffer)); new KeyImportDetailDialog(mCtx, result, false, this); } @@ -397,7 +379,7 @@ void KeyList::getCheckedKeys(QVector<GpgKey> &keys) { void KeyList::setExcludeKeys(std::initializer_list<QString> key_ids) { excluded_key_ids.clear(); - for(auto &key_id : key_ids) { + for (auto &key_id : key_ids) { excluded_key_ids.push_back(key_id); } } @@ -407,7 +389,7 @@ void KeyList::setFilter(std::function<bool(const GpgKey &)> filter) { } void KeyList::slotDoubleClicked(const QModelIndex &index) { - if(mAction != nullptr) { + if (mAction != nullptr) { const auto &key = mCtx->getKeyById(buffered_keys[index.row()].id); mAction(key, this); } |