/** * 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 . * * 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 starting on May 12, 2021. * */ #include "ui/keypair_details/KeyPairDetailTab.h" #include "gpg/function/GpgKeyGetter.h" #include "gpg/function/GpgKeyImportExportor.h" #include "ui/SignalStation.h" #include "ui/WaitingDialog.h" namespace GpgFrontend::UI { KeyPairDetailTab::KeyPairDetailTab(const std::string& key_id, QWidget* parent) : QWidget(parent), mKey(GpgKeyGetter::GetInstance().GetKey(key_id)) { keyid = mKey.id(); ownerBox = new QGroupBox(_("Owner")); keyBox = new QGroupBox(_("Master Key")); fingerprintBox = new QGroupBox(_("Fingerprint")); additionalUidBox = new QGroupBox(_("Additional UIDs")); nameVarLabel = new QLabel(); nameVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); emailVarLabel = new QLabel(); emailVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); commentVarLabel = new QLabel(); commentVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); keyidVarLabel = new QLabel(); keyidVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); usageVarLabel = new QLabel(); actualUsageVarLabel = new QLabel(); keySizeVarLabel = new QLabel(); expireVarLabel = new QLabel(); createdVarLabel = new QLabel(); algorithmVarLabel = new QLabel(); // Show the situation that master key not exists. masterKeyExistVarLabel = new QLabel(mKey.has_master_key() ? _("Exists") : _("Not Exists")); if (!mKey.has_master_key()) { auto paletteExpired = masterKeyExistVarLabel->palette(); paletteExpired.setColor(masterKeyExistVarLabel->foregroundRole(), Qt::red); masterKeyExistVarLabel->setPalette(paletteExpired); } else { auto paletteValid = masterKeyExistVarLabel->palette(); paletteValid.setColor(masterKeyExistVarLabel->foregroundRole(), Qt::darkGreen); masterKeyExistVarLabel->setPalette(paletteValid); } if (mKey.expired()) { auto paletteExpired = expireVarLabel->palette(); paletteExpired.setColor(expireVarLabel->foregroundRole(), Qt::red); expireVarLabel->setPalette(paletteExpired); } else { auto paletteValid = expireVarLabel->palette(); paletteValid.setColor(expireVarLabel->foregroundRole(), Qt::darkGreen); expireVarLabel->setPalette(paletteValid); } auto* mvbox = new QVBoxLayout(); auto* vboxKD = new QGridLayout(); auto* vboxOD = new QGridLayout(); vboxOD->addWidget(new QLabel(QString(_("Name")) + ": "), 0, 0); vboxOD->addWidget(new QLabel(QString(_("Email Address")) + ": "), 1, 0); vboxOD->addWidget(new QLabel(QString(_("Comment")) + ": "), 2, 0); vboxOD->addWidget(nameVarLabel, 0, 1); vboxOD->addWidget(emailVarLabel, 1, 1); vboxOD->addWidget(commentVarLabel, 2, 1); vboxKD->addWidget(new QLabel(QString(_("Key ID")) + ": "), 0, 0); vboxKD->addWidget(new QLabel(QString(_("Algorithm")) + ": "), 1, 0); vboxKD->addWidget(new QLabel(QString(_("Key Size")) + ": "), 2, 0); vboxKD->addWidget(new QLabel(QString(_("Nominal Usage")) + ": "), 3, 0); vboxKD->addWidget(new QLabel(QString(_("Actual Usage")) + ": "), 4, 0); vboxKD->addWidget(new QLabel(QString(_("Expires on")) + ": "), 5, 0); vboxKD->addWidget(new QLabel(QString(_("Last Update")) + ": "), 6, 0); vboxKD->addWidget(new QLabel(QString(_("Secret Key Existence")) + ": "), 7, 0); vboxKD->addWidget(keySizeVarLabel, 2, 1); vboxKD->addWidget(expireVarLabel, 5, 1); vboxKD->addWidget(algorithmVarLabel, 1, 1); vboxKD->addWidget(createdVarLabel, 6, 1); vboxKD->addWidget(keyidVarLabel, 0, 1); vboxKD->addWidget(usageVarLabel, 3, 1); vboxKD->addWidget(actualUsageVarLabel, 4, 1); vboxKD->addWidget(masterKeyExistVarLabel, 7, 1); ownerBox->setLayout(vboxOD); mvbox->addWidget(ownerBox); keyBox->setLayout(vboxKD); mvbox->addWidget(keyBox); fingerPrintVarLabel = new QLabel(beautifyFingerprint(QString::fromStdString(mKey.fpr()))); fingerPrintVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); fingerPrintVarLabel->setStyleSheet("margin-left: 0; margin-right: 5;"); auto* hboxFP = new QHBoxLayout(); hboxFP->addWidget(fingerPrintVarLabel); auto* copyFingerprintButton = new QPushButton(_("Copy")); copyFingerprintButton->setFlat(true); copyFingerprintButton->setToolTip(_("copy fingerprint to clipboard")); connect(copyFingerprintButton, SIGNAL(clicked()), this, SLOT(slotCopyFingerprint())); hboxFP->addWidget(copyFingerprintButton); fingerprintBox->setLayout(hboxFP); mvbox->addWidget(fingerprintBox); mvbox->addStretch(); if (mKey.is_private_key()) { auto* privKeyBox = new QGroupBox(_("Operations")); auto* vboxPK = new QVBoxLayout(); auto* exportButton = new QPushButton(_("Export Private Key (Include Subkey)")); vboxPK->addWidget(exportButton); connect(exportButton, SIGNAL(clicked()), this, SLOT(slotExportPrivateKey())); if (mKey.has_master_key()) { auto* editExpiresButton = new QPushButton(_("Modify Expiration Datetime (Master Key)")); vboxPK->addWidget(editExpiresButton); connect(editExpiresButton, SIGNAL(clicked()), this, SLOT(slotModifyEditDatetime())); auto hBoxLayout = new QHBoxLayout(); auto* keyServerOperaButton = new QPushButton(_("Key Server Operation (Pubkey)")); keyServerOperaButton->setStyleSheet("text-align:center;"); auto* revokeCertGenButton = new QPushButton(_("Generate Revoke Certificate")); connect(revokeCertGenButton, SIGNAL(clicked()), this, SLOT(slotGenRevokeCert())); hBoxLayout->addWidget(keyServerOperaButton); hBoxLayout->addWidget(revokeCertGenButton); vboxPK->addLayout(hBoxLayout); connect(keyServerOperaButton, SIGNAL(clicked()), this, SLOT(slotModifyEditDatetime())); // Set Menu createKeyServerOperaMenu(); keyServerOperaButton->setMenu(keyServerOperaMenu); } privKeyBox->setLayout(vboxPK); mvbox->addWidget(privKeyBox); } if ((mKey.expired()) || (mKey.revoked())) { auto* expBox = new QHBoxLayout(); QPixmap pixmap(":warning.png"); auto* expLabel = new QLabel(); auto* iconLabel = new QLabel(); if (mKey.expired()) { expLabel->setText(_("Warning: The Master Key has expired.")); } if (mKey.revoked()) { expLabel->setText(_("Warning: The Master Key has been revoked")); } iconLabel->setPixmap(pixmap.scaled(24, 24, Qt::KeepAspectRatio)); QFont font = expLabel->font(); font.setBold(true); expLabel->setFont(font); expLabel->setAlignment(Qt::AlignCenter); expBox->addWidget(iconLabel); expBox->addWidget(expLabel); mvbox->addLayout(expBox); } // when key database updated connect(SignalStation::GetInstance(), SIGNAL(KeyDatabaseRefresh()), this, SLOT(slotRefreshKey())); mvbox->setContentsMargins(0, 0, 0, 0); slotRefreshKeyInfo(); setAttribute(Qt::WA_DeleteOnClose, true); setLayout(mvbox); } void KeyPairDetailTab::slotExportPrivateKey() { // Show a information box with explanation about private key int ret = QMessageBox::information( this, _("Exporting private Key"), "

" + QString(_("You are about to export your")) + "" + _(" PRIVATE KEY ") + "!

\n" + _("This is NOT your Public Key, so DON'T give it away.") + "
" + _("Do you REALLY want to export your PRIVATE KEY?"), QMessageBox::Cancel | QMessageBox::Ok); // export key, if ok was clicked if (ret == QMessageBox::Ok) { ByteArrayPtr keyArray = nullptr; if (!GpgKeyImportExportor::GetInstance().ExportSecretKey(mKey, keyArray)) { QMessageBox::critical(this, "Error", "An error occurred during the export operation."); return; } auto key = GpgKeyGetter::GetInstance().GetKey(keyid); if (!key.good()) { QMessageBox::critical(nullptr, _("Error"), _("Key Not Found.")); return; } auto fileString = key.name() + " " + key.email() + "(" + key.id() + ")_secret.asc"; auto fileName = QFileDialog::getSaveFileName( this, _("Export Key To File"), QString::fromStdString(fileString), QString(_("Key Files")) + " (*.asc *.txt);;All Files (*)") .toStdString(); if (!write_buffer_to_file(fileName, *keyArray)) { QMessageBox::critical( nullptr, _("Export Error"), QString(_("Couldn't open %1 for writing")).arg(fileName.c_str())); return; } } } QString KeyPairDetailTab::beautifyFingerprint(QString fingerprint) { uint len = fingerprint.length(); if ((len > 0) && (len % 4 == 0)) for (uint n = 0; 4 * (n + 1) < len; ++n) fingerprint.insert(static_cast(5u * n + 4u), ' '); return fingerprint; } void KeyPairDetailTab::slotCopyFingerprint() { QString fpr = fingerPrintVarLabel->text().trimmed().replace(" ", QString()); QClipboard* cb = QApplication::clipboard(); cb->setText(fpr); } void KeyPairDetailTab::slotModifyEditDatetime() { auto dialog = new KeySetExpireDateDialog(mKey.id(), this); dialog->show(); } void KeyPairDetailTab::slotRefreshKeyInfo() { nameVarLabel->setText(QString::fromStdString(mKey.name())); emailVarLabel->setText(QString::fromStdString(mKey.email())); commentVarLabel->setText(QString::fromStdString(mKey.comment())); keyidVarLabel->setText(QString::fromStdString(mKey.id())); QString usage; QTextStream usage_steam(&usage); if (mKey.can_certify()) usage_steam << _("Cert") << " "; if (mKey.can_encrypt()) usage_steam << _("Encr") << " "; if (mKey.can_sign()) usage_steam << _("Sign") << " "; if (mKey.can_authenticate()) usage_steam << _("Auth") << " "; usageVarLabel->setText(usage); QString actualUsage; QTextStream actual_usage_steam(&actualUsage); if (mKey.CanCertActual()) actual_usage_steam << _("Cert") << " "; if (mKey.CanEncrActual()) actual_usage_steam << _("Encr") << " "; if (mKey.CanSignActual()) actual_usage_steam << _("Sign") << " "; if (mKey.CanAuthActual()) actual_usage_steam << _("Auth") << " "; actualUsageVarLabel->setText(actualUsage); QString keySizeVal, keyExpireVal, keyCreateTimeVal, keyAlgoVal; keySizeVal = QString::number(mKey.length()); if (to_time_t(boost::posix_time::ptime(mKey.expires())) == 0) { keyExpireVal = _("Never Expire"); } else { keyExpireVal = QString::fromStdString(boost::gregorian::to_iso_string(mKey.expires())); } keyAlgoVal = QString::fromStdString(mKey.pubkey_algo()); keyCreateTimeVal = QString::fromStdString(to_iso_string(mKey.create_time())); keySizeVarLabel->setText(keySizeVal); expireVarLabel->setText(keyExpireVal); createdVarLabel->setText(keyCreateTimeVal); algorithmVarLabel->setText(keyAlgoVal); auto key_fpr = mKey.fpr(); fingerPrintVarLabel->setText( QString::fromStdString(beautify_fingerprint(key_fpr))); } void KeyPairDetailTab::createKeyServerOperaMenu() { keyServerOperaMenu = new QMenu(this); auto* uploadKeyPair = new QAction(_("Upload Key Pair to Key Server"), this); connect(uploadKeyPair, SIGNAL(triggered()), this, SLOT(slotUploadKeyToServer())); auto* updateKeyPair = new QAction(_("Update Key Pair"), this); connect(updateKeyPair, SIGNAL(triggered()), this, SLOT(slotUpdateKeyToServer())); keyServerOperaMenu->addAction(uploadKeyPair); keyServerOperaMenu->addAction(updateKeyPair); } void KeyPairDetailTab::slotUploadKeyToServer() { auto keys = std::make_unique(); keys->push_back(mKey.id()); auto* dialog = new KeyUploadDialog(keys, this); dialog->show(); dialog->slotUpload(); } void KeyPairDetailTab::slotUpdateKeyToServer() { auto keys = std::make_unique(); keys->push_back(mKey.id()); auto* dialog = new KeyServerImportDialog(this); dialog->show(); dialog->slotImport(keys); } void KeyPairDetailTab::slotGenRevokeCert() { auto mOutputFileName = QFileDialog::getSaveFileName( this, _("Generate revocation certificate"), QString(), QStringLiteral("%1 (*.rev)").arg(_("Revocation Certificates"))); // if (!mOutputFileName.isEmpty()) // mCtx->generateRevokeCert(mKey, mOutputFileName); } void KeyPairDetailTab::slotRefreshKey() { LOG(INFO) << "KeyPairDetailTab::slotRefreshKey Called"; this->mKey = GpgKeyGetter::GetInstance().GetKey(mKey.id()); this->slotRefreshKeyInfo(); } } // namespace GpgFrontend::UI