/** * Copyright (C) 2021-2024 Saturneric * * 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 . * * 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 starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ #include "SmartCardControllerDialog.h" #include "core/function/gpg/GpgAssuanHelper.h" #include "core/utils/GpgUtils.h" // #include "ui_SmartCardControllerDialog.h" namespace GpgFrontend::UI { SmartCardControllerDialog::SmartCardControllerDialog(QWidget* parent) : GeneralDialog("SmartCardControllerDialog", parent), ui_(QSharedPointer::create()), channel_(kGpgFrontendDefaultChannel) { ui_->setupUi(this); for (const auto& key_db : GetGpgKeyDatabaseInfos()) { ui_->keyDBIndexComboBox->insertItem( key_db.channel, QString("%1: %2").arg(key_db.channel).arg(key_db.name)); } connect(ui_->keyDBIndexComboBox, qOverload(&QComboBox::currentIndexChanged), this, [=](int index) { channel_ = index; ui_->cardKeysTreeView->SetChannel(channel_); ui_->cardKeysTreeView->expandAll(); }); slot_refresh(); } void SmartCardControllerDialog::get_smart_card_serial_number() { auto [ret, status] = GpgAssuanHelper::GetInstance().SendStatusCommand( GpgComponentType::kGPG_AGENT, "SCD SERIALNO --all openpgp"); if (!ret || status.isEmpty()) return; auto line = status.front(); auto token = line.split(' '); if (token.size() != 2) { LOG_E() << "invalid response of command SERIALNO: " << line; return; } serial_number_ = token.back().trimmed(); LOG_D() << "get smart card serial number: " << serial_number_; } void SmartCardControllerDialog::fetch_smart_card_info() { if (serial_number_.isEmpty()) return; auto [ret, status] = GpgAssuanHelper::GetInstance().SendStatusCommand( GpgComponentType::kGPG_AGENT, "SCD LEARN --force " + serial_number_); if (!ret || status.isEmpty()) return; LOG_D() << "fetch card raw info: " << status; card_info_ = GpgOpenPGPCard(status); if (!card_info_.good) { LOG_E() << "parse card raw info failed"; return; } } void SmartCardControllerDialog::print_smart_card_info() { if (!card_info_.good) return; QString html; QTextStream out(&html); auto card = card_info_; out << "

" << tr("OpenPGP Card Information") << "

"; out << "

" << tr("Basic Information") << "

    "; out << "
  • " << tr("Reader:") << " " << card.reader << "
  • "; out << "
  • " << tr("Serial Number:") << " " << card.serial_number << "
  • "; out << "
  • " << tr("Card Type:") << " " << card.card_type << "
  • "; out << "
  • " << tr("Card Version:") << " " << card.card_version << "
  • "; out << "
  • " << tr("App Type:") << " " << card.app_type << "
  • "; out << "
  • " << tr("App Version:") << " " << card.app_version << "
  • "; out << "
  • " << tr("Manufacturer:") << " " << card.manufacturer << "
  • "; out << "
  • " << tr("Card Holder:") << " " << card.card_holder << "
  • "; out << "
  • " << tr("Language:") << " " << card.display_language << "
  • "; out << "
  • " << tr("Sex:") << " " << card.display_sex << "
  • "; out << "
"; out << "

" << tr("Status") << "

    "; out << "
  • " << tr("CHV Status:") << " " << card.chv_status << "
  • "; out << "
  • " << tr("Signature Counter:") << " " << card.sig_counter << "
  • "; out << "
  • " << tr("KDF:") << " " << card.kdf << "
  • "; out << "
  • " << tr("UIF1:") << " " << card.uif1 << "
  • "; out << "
  • " << tr("UIF2:") << " " << card.uif2 << "
  • "; out << "
  • " << tr("UIF3:") << " " << card.uif3 << "
  • "; out << "
"; out << "

" << tr("Fingerprints") << "

    "; for (auto it = card.fprs.begin(); it != card.fprs.end(); ++it) { out << "
  • " << tr("Key %1:").arg(it.key()) << " " << it.value() << "
  • "; } out << "
"; if (!card.card_infos.isEmpty()) { out << "

" << tr("Additional Info") << "

    "; for (auto it = card.card_infos.begin(); it != card.card_infos.end(); ++it) { out << "
  • " << tr("%1:").arg(it.key()) << " " << it.value() << "
  • "; } out << "
"; } ui_->cardInfoEdit->setText(html); } void SmartCardControllerDialog::slot_refresh() { ui_->cardInfoEdit->clear(); get_smart_card_serial_number(); fetch_smart_card_info(); print_smart_card_info(); refresh_key_tree_view(); } void SmartCardControllerDialog::refresh_key_tree_view() { if (card_info_.fprs.isEmpty()) { ui_->cardKeysTreeView->SetKeyFilter([](auto) { return false; }); return; } QStringList card_fprs(card_info_.fprs.begin(), card_info_.fprs.end()); ui_->cardKeysTreeView->SetKeyFilter([=](const GpgAbstractKey* k) { return card_fprs.contains(k->Fingerprint()); }); } } // namespace GpgFrontend::UI