keepassxc
190 строк · 6.8 Кб
1/*
2* Copyright (C) 2018 KeePassXC Team <team@keepassxc.org>
3*
4* This program is free software: you can redistribute it and/or modify
5* it under the terms of the GNU General Public License as published by
6* the Free Software Foundation, either version 2 or (at your option)
7* version 3 of the License.
8*
9* This program is distributed in the hope that it will be useful,
10* but WITHOUT ANY WARRANTY; without even the implied warranty of
11* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12* GNU General Public License for more details.
13*
14* You should have received a copy of the GNU General Public License
15* along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include "YubiKeyEditWidget.h"19
20#include "ui_KeyComponentWidget.h"21#include "ui_YubiKeyEditWidget.h"22
23#include "core/AsyncTask.h"24#include "gui/Icons.h"25#include "keys/ChallengeResponseKey.h"26#include "keys/CompositeKey.h"27#ifdef WITH_XC_YUBIKEY28#include "keys/drivers/YubiKeyInterfaceUSB.h"29#endif30
31YubiKeyEditWidget::YubiKeyEditWidget(QWidget* parent)32: KeyComponentWidget(parent)33, m_compUi(new Ui::YubiKeyEditWidget())34#ifdef WITH_XC_YUBIKEY35, m_deviceListener(new DeviceListener(this))36#endif37{
38initComponent();39#ifdef WITH_XC_YUBIKEY40connect(YubiKey::instance(), SIGNAL(detectComplete(bool)), SLOT(hardwareKeyResponse(bool)), Qt::QueuedConnection);41connect(m_deviceListener, &DeviceListener::devicePlugged, this, [&](bool, void*, void*) { pollYubikey(); });42#endif43}
44
45YubiKeyEditWidget::~YubiKeyEditWidget() = default;46
47bool YubiKeyEditWidget::addToCompositeKey(QSharedPointer<CompositeKey> key)48{
49if (!m_isDetected || !m_compEditWidget) {50return false;51}52
53int selectionIndex = m_compUi->comboChallengeResponse->currentIndex();54auto slot = m_compUi->comboChallengeResponse->itemData(selectionIndex).value<YubiKeySlot>();55key->addChallengeResponseKey(QSharedPointer<ChallengeResponseKey>::create(slot));56return true;57}
58
59bool YubiKeyEditWidget::validate(QString& errorMessage) const60{
61if (!m_isDetected) {62errorMessage = tr("Could not find any hardware keys!");63return false;64}65
66// Perform a test challenge response67int selectionIndex = m_compUi->comboChallengeResponse->currentIndex();68auto slot = m_compUi->comboChallengeResponse->itemData(selectionIndex).value<YubiKeySlot>();69bool valid = AsyncTask::runAndWaitForFuture([&slot] { return YubiKey::instance()->testChallenge(slot); });70if (!valid) {71errorMessage = tr("Selected hardware key slot does not support challenge-response!");72}73return valid;74}
75
76QWidget* YubiKeyEditWidget::componentEditWidget()77{
78m_compEditWidget = new QWidget();79m_compUi->setupUi(m_compEditWidget);80
81QSizePolicy sp = m_compUi->yubikeyProgress->sizePolicy();82sp.setRetainSizeWhenHidden(true);83m_compUi->yubikeyProgress->setSizePolicy(sp);84m_compUi->yubikeyProgress->setVisible(false);85
86return m_compEditWidget;87}
88
89void YubiKeyEditWidget::showEvent(QShowEvent* event)90{
91KeyComponentWidget::showEvent(event);92
93#ifdef WITH_XC_YUBIKEY94#ifdef Q_OS_WIN95m_deviceListener->registerHotplugCallback(true,96true,97YubiKeyInterfaceUSB::YUBICO_USB_VID,98DeviceListener::MATCH_ANY,99&DeviceListenerWin::DEV_CLS_KEYBOARD);100m_deviceListener->registerHotplugCallback(true,101true,102YubiKeyInterfaceUSB::ONLYKEY_USB_VID,103DeviceListener::MATCH_ANY,104&DeviceListenerWin::DEV_CLS_KEYBOARD);105#else106m_deviceListener->registerHotplugCallback(true, true, YubiKeyInterfaceUSB::YUBICO_USB_VID);107m_deviceListener->registerHotplugCallback(true, true, YubiKeyInterfaceUSB::ONLYKEY_USB_VID);108#endif109#endif110}
111
112void YubiKeyEditWidget::hideEvent(QHideEvent* event)113{
114KeyComponentWidget::hideEvent(event);115#ifdef WITH_XC_YUBIKEY116m_deviceListener->deregisterAllHotplugCallbacks();117#endif118}
119
120void YubiKeyEditWidget::initComponentEditWidget(QWidget* widget)121{
122Q_UNUSED(widget);123Q_ASSERT(m_compEditWidget);124m_compUi->comboChallengeResponse->setFocus();125m_compUi->refreshHardwareKeys->setIcon(icons()->icon("yubikey-refresh", true));126connect(m_compUi->refreshHardwareKeys, &QPushButton::clicked, this, &YubiKeyEditWidget::pollYubikey);127pollYubikey();128}
129
130void YubiKeyEditWidget::initComponent()131{
132// These need to be set in total for each credential type for translation purposes133m_ui->groupBox->setTitle(tr("Challenge-Response"));134m_ui->addButton->setText(tr("Add Challenge-Response"));135m_ui->changeButton->setText(tr("Change Challenge-Response"));136m_ui->removeButton->setText(tr("Remove Challenge-Response"));137m_ui->changeOrRemoveLabel->setText(tr("Challenge-Response set, click to change or remove"));138
139m_ui->componentDescription->setText(140tr("<p>If you own a <a href=\"https://www.yubico.com/\">YubiKey</a> or "141"<a href=\"https://onlykey.io\">OnlyKey</a>, you can use it for additional security.</p>"142"<p>The key requires one of its slots to be programmed as "143"<a href=\"https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html\">"144"HMAC-SHA1 Challenge-Response</a>.</p>"));145}
146
147void YubiKeyEditWidget::pollYubikey()148{
149#ifdef WITH_XC_YUBIKEY150if (!m_compEditWidget) {151return;152}153
154m_isDetected = false;155m_compUi->comboChallengeResponse->clear();156m_compUi->comboChallengeResponse->addItem(tr("Detecting hardware keys…"));157m_compUi->comboChallengeResponse->setEnabled(false);158m_compUi->yubikeyProgress->setVisible(true);159m_compUi->refreshHardwareKeys->setEnabled(false);160
161YubiKey::instance()->findValidKeysAsync();162#endif163}
164
165void YubiKeyEditWidget::hardwareKeyResponse(bool found)166{
167if (!m_compEditWidget) {168return;169}170
171m_compUi->comboChallengeResponse->clear();172m_compUi->refreshHardwareKeys->setEnabled(true);173
174if (!found) {175m_compUi->yubikeyProgress->setVisible(false);176m_compUi->comboChallengeResponse->addItem(tr("No hardware keys detected"));177m_isDetected = false;178return;179}180
181const auto foundKeys = YubiKey::instance()->foundKeys();182for (auto i = foundKeys.cbegin(); i != foundKeys.cend(); ++i) {183// add detected YubiKey to combo box and encode blocking mode in LSB, slot number in second LSB184m_compUi->comboChallengeResponse->addItem(i.value(), QVariant::fromValue(i.key()));185}186
187m_isDetected = true;188m_compUi->yubikeyProgress->setVisible(false);189m_compUi->comboChallengeResponse->setEnabled(true);190}
191