/** * 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/KeyPairSubkeyTab.h" #include "gpg/function/GpgKeyGetter.h" #include "ui/SignalStation.h" namespace GpgFrontend::UI { KeyPairSubkeyTab::KeyPairSubkeyTab(const std::string& key_id, QWidget* parent) : QWidget(parent), mKey(GpgKeyGetter::GetInstance().GetKey(key_id)) { createSubkeyList(); createSubkeyOperaMenu(); listBox = new QGroupBox("Subkey List"); detailBox = new QGroupBox("Detail of Selected Subkey"); auto uidButtonsLayout = new QGridLayout(); auto addSubkeyButton = new QPushButton(_("Generate A New Subkey")); if (!mKey.is_private_key() || !mKey.has_master_key()) { addSubkeyButton->setDisabled(true); setHidden(addSubkeyButton); } uidButtonsLayout->addWidget(addSubkeyButton, 0, 1); auto* baseLayout = new QVBoxLayout(); auto subkeyListLayout = new QGridLayout(); subkeyListLayout->addWidget(subkeyList, 0, 0); subkeyListLayout->addLayout(uidButtonsLayout, 1, 0); subkeyListLayout->setContentsMargins(0, 10, 0, 0); auto* subkeyDetailLayout = new QGridLayout(); subkeyDetailLayout->addWidget(new QLabel(QString(_("Key ID")) + ": "), 0, 0); subkeyDetailLayout->addWidget(new QLabel(QString(_("Algorithm")) + ": "), 1, 0); subkeyDetailLayout->addWidget(new QLabel(QString(_("Key Size")) + ": "), 2, 0); subkeyDetailLayout->addWidget(new QLabel(QString(_("Usage")) + ": "), 3, 0); subkeyDetailLayout->addWidget(new QLabel(QString(_("Expires On")) + ": "), 4, 0); subkeyDetailLayout->addWidget(new QLabel(QString(_("Last Update")) + ": "), 5, 0); subkeyDetailLayout->addWidget(new QLabel(QString(_("Existence")) + ": "), 6, 0); subkeyDetailLayout->addWidget(new QLabel(QString(_("Fingerprint")) + ": "), 7, 0); keyidVarLabel = new QLabel(); keySizeVarLabel = new QLabel(); expireVarLabel = new QLabel(); algorithmVarLabel = new QLabel(); createdVarLabel = new QLabel(); usageVarLabel = new QLabel(); masterKeyExistVarLabel = new QLabel(); fingerPrintVarLabel = new QLabel(); subkeyDetailLayout->addWidget(keyidVarLabel, 0, 1); subkeyDetailLayout->addWidget(keySizeVarLabel, 2, 1); subkeyDetailLayout->addWidget(expireVarLabel, 4, 1); subkeyDetailLayout->addWidget(algorithmVarLabel, 1, 1); subkeyDetailLayout->addWidget(createdVarLabel, 5, 1); subkeyDetailLayout->addWidget(usageVarLabel, 3, 1); subkeyDetailLayout->addWidget(masterKeyExistVarLabel, 6, 1); subkeyDetailLayout->addWidget(fingerPrintVarLabel, 7, 1); listBox->setLayout(subkeyListLayout); listBox->setContentsMargins(0, 5, 0, 0); detailBox->setLayout(subkeyDetailLayout); baseLayout->addWidget(listBox); baseLayout->addWidget(detailBox); baseLayout->addStretch(); connect(addSubkeyButton, SIGNAL(clicked(bool)), this, SLOT(slotAddSubkey())); connect(subkeyList, SIGNAL(itemSelectionChanged()), this, SLOT(slotRefreshSubkeyDetail())); // key database refresh signal connect(SignalStation::GetInstance(), SIGNAL(KeyDatabaseRefresh()), this, SLOT(slotRefreshKeyInfo())); connect(SignalStation::GetInstance(), SIGNAL(KeyDatabaseRefresh()), this, SLOT(slotRefreshSubkeyList())); baseLayout->setContentsMargins(0, 0, 0, 0); setLayout(baseLayout); setAttribute(Qt::WA_DeleteOnClose, true); slotRefreshSubkeyList(); } void KeyPairSubkeyTab::createSubkeyList() { subkeyList = new QTableWidget(this); subkeyList->setColumnCount(5); subkeyList->horizontalHeader()->setSectionResizeMode( QHeaderView::ResizeToContents); subkeyList->verticalHeader()->hide(); subkeyList->setShowGrid(false); subkeyList->setSelectionBehavior(QAbstractItemView::SelectRows); // tableitems not editable subkeyList->setEditTriggers(QAbstractItemView::NoEditTriggers); // no focus (rectangle around tableitems) // may be it should focus on whole row subkeyList->setFocusPolicy(Qt::NoFocus); subkeyList->setAlternatingRowColors(true); QStringList labels; labels << _("Subkey ID") << _("Key Size") << _("Algo") << _("Create Date") << _("Expire Date"); subkeyList->setHorizontalHeaderLabels(labels); subkeyList->horizontalHeader()->setStretchLastSection(false); } void KeyPairSubkeyTab::slotRefreshSubkeyList() { LOG(INFO) << "KeyPairSubkeyTab::slotRefreshSubkeyList Called"; int row = 0; subkeyList->setSelectionMode(QAbstractItemView::SingleSelection); this->buffered_subkeys.clear(); auto sub_keys = mKey.subKeys(); for (auto& sub_key : *sub_keys) { if (sub_key.disabled() || sub_key.revoked()) continue; this->buffered_subkeys.push_back(std::move(sub_key)); } subkeyList->setRowCount(buffered_subkeys.size()); for (const auto& subkeys : buffered_subkeys) { auto* tmp0 = new QTableWidgetItem(QString::fromStdString(subkeys.id())); tmp0->setTextAlignment(Qt::AlignCenter); subkeyList->setItem(row, 0, tmp0); auto* tmp1 = new QTableWidgetItem(QString::number(subkeys.length())); tmp1->setTextAlignment(Qt::AlignCenter); subkeyList->setItem(row, 1, tmp1); auto* tmp2 = new QTableWidgetItem(QString::fromStdString(subkeys.pubkey_algo())); tmp2->setTextAlignment(Qt::AlignCenter); subkeyList->setItem(row, 2, tmp2); auto* tmp3 = new QTableWidgetItem( QString::fromStdString(to_iso_string(subkeys.timestamp()))); tmp3->setTextAlignment(Qt::AlignCenter); subkeyList->setItem(row, 3, tmp3); auto* tmp4 = new QTableWidgetItem( boost::posix_time::to_time_t( boost::posix_time::ptime(subkeys.expires())) == 0 ? _("Never Expire") : QString::fromStdString(to_iso_string(subkeys.expires()))); tmp4->setTextAlignment(Qt::AlignCenter); subkeyList->setItem(row, 4, tmp4); if (!row) { for (auto i = 0; i < subkeyList->columnCount(); i++) { subkeyList->item(row, i)->setTextColor(QColor(65, 105, 255)); } } row++; } if (subkeyList->rowCount() > 0) { subkeyList->selectRow(0); } } void KeyPairSubkeyTab::slotAddSubkey() { auto dialog = new SubkeyGenerateDialog(mKey.id(), this); dialog->show(); } void KeyPairSubkeyTab::slotRefreshSubkeyDetail() { auto& subkey = getSelectedSubkey(); keyidVarLabel->setText(QString::fromStdString(subkey.id())); keySizeVarLabel->setText(QString::number(subkey.length())); time_t subkey_time_t = boost::posix_time::to_time_t(boost::posix_time::ptime(subkey.expires())); expireVarLabel->setText( subkey_time_t == 0 ? _("Never Expires") : QString::fromStdString(to_iso_string(subkey.expires()))); if (subkey_time_t != 0 && subkey.expires() < boost::posix_time::second_clock::local_time().date()) { 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); } algorithmVarLabel->setText(QString::fromStdString(subkey.pubkey_algo())); createdVarLabel->setText( QString::fromStdString(to_iso_string(subkey.timestamp()))); QString usage; QTextStream usage_steam(&usage); if (subkey.can_certify()) usage_steam << _("Cert") << " "; if (subkey.can_encrypt()) usage_steam << _("Encr") << " "; if (subkey.can_sign()) usage_steam << _("Sign") << " "; if (subkey.can_authenticate()) usage_steam << _("Auth") << " "; usageVarLabel->setText(usage); // Show the situation that master key not exists. masterKeyExistVarLabel->setText(subkey.secret() ? _("Exists") : _("Not Exists")); if (!subkey.secret()) { 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); } fingerPrintVarLabel->setText(QString::fromStdString(subkey.fpr())); } void KeyPairSubkeyTab::createSubkeyOperaMenu() { subkeyOperaMenu = new QMenu(this); // auto *revokeSubkeyAct = new QAction(_("Revoke Subkey")); auto* editSubkeyAct = new QAction(_("Edit Expire Date")); connect(editSubkeyAct, SIGNAL(triggered(bool)), this, SLOT(slotEditSubkey())); // subkeyOperaMenu->addAction(revokeSubkeyAct); subkeyOperaMenu->addAction(editSubkeyAct); } void KeyPairSubkeyTab::slotEditSubkey() { LOG(INFO) << "KeyPairSubkeyTab::slotEditSubkey Fpr" << getSelectedSubkey().fpr(); auto dialog = new KeySetExpireDateDialog(mKey.id(), getSelectedSubkey().fpr(), this); dialog->show(); } void KeyPairSubkeyTab::slotRevokeSubkey() {} void KeyPairSubkeyTab::contextMenuEvent(QContextMenuEvent* event) { if (!subkeyList->selectedItems().isEmpty()) { subkeyOperaMenu->exec(event->globalPos()); } } const GpgSubKey& KeyPairSubkeyTab::getSelectedSubkey() { int row = 0; for (int i = 0; i < subkeyList->rowCount(); i++) { if (subkeyList->item(row, 0)->isSelected()) break; row++; } return buffered_subkeys[row]; } void KeyPairSubkeyTab::slotRefreshKeyInfo() { mKey = GpgKeyGetter::GetInstance().GetKey(mKey.id()); } } // namespace GpgFrontend::UI