Replace "Master Key" with "Database Credentials"

Definitions:
* Database Key - Cryptographic hash used to perform encrypt/decrypt of the database.

* Database Credentials - User facing term to refer to the collection of Password, Key File, and/or Hardware Key used to derive the Database Key.

Changes:
* Remove the term "master" and "key" from the user's lexicon and clarify  the code base based on the definitions above.
* Clean up wording in the UI to be clearer to the end user.
This commit is contained in:
Jonathan White 2020-07-01 19:16:40 -04:00
parent 60bb593228
commit 3b459813ed
45 changed files with 162 additions and 162 deletions

View file

@ -0,0 +1,201 @@
/*
* Copyright (C) 2018 KeePassXC Team <team@keepassxc.org>
*
* This program 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 2 or (at your option)
* version 3 of the License.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "KeyComponentWidget.h"
#include "ui_KeyComponentWidget.h"
#include <QStackedWidget>
#include <QTimer>
KeyComponentWidget::KeyComponentWidget(QWidget* parent)
: KeyComponentWidget({}, parent)
{
}
KeyComponentWidget::KeyComponentWidget(const QString& name, QWidget* parent)
: QWidget(parent)
, m_ui(new Ui::KeyComponentWidget())
{
m_ui->setupUi(this);
connect(m_ui->addButton, SIGNAL(clicked(bool)), SIGNAL(componentAddRequested()));
connect(m_ui->changeButton, SIGNAL(clicked(bool)), SIGNAL(componentEditRequested()));
connect(m_ui->removeButton, SIGNAL(clicked(bool)), SIGNAL(componentRemovalRequested()));
connect(m_ui->cancelButton, SIGNAL(clicked(bool)), SLOT(cancelEdit()));
connect(m_ui->stackedWidget, SIGNAL(currentChanged(int)), SLOT(resetComponentEditWidget()));
connect(this, SIGNAL(nameChanged(QString)), SLOT(updateComponentName(QString)));
connect(this, SIGNAL(descriptionChanged(QString)), SLOT(updateComponentDescription(QString)));
connect(this, SIGNAL(componentAddRequested()), SLOT(doAdd()));
connect(this, SIGNAL(componentEditRequested()), SLOT(doEdit()));
connect(this, SIGNAL(componentRemovalRequested()), SLOT(doRemove()));
connect(this, SIGNAL(componentAddChanged(bool)), SLOT(updateAddStatus(bool)));
bool prev = blockSignals(true);
setComponentName(name);
blockSignals(prev);
prev = m_ui->stackedWidget->blockSignals(true);
m_ui->stackedWidget->setCurrentIndex(Page::AddNew);
m_ui->stackedWidget->blockSignals(prev);
}
KeyComponentWidget::~KeyComponentWidget()
{
}
/**
* @param name display name for the key component
*/
void KeyComponentWidget::setComponentName(const QString& name)
{
if (name == m_componentName) {
return;
}
m_componentName = name;
emit nameChanged(name);
}
/**
* @return The key component's display name
*/
QString KeyComponentWidget::componentName() const
{
return m_componentName;
}
void KeyComponentWidget::setComponentDescription(const QString& description)
{
if (description == m_componentDescription) {
return;
}
m_componentDescription = description;
emit descriptionChanged(description);
}
QString KeyComponentWidget::componentDescription() const
{
return m_componentDescription;
}
void KeyComponentWidget::setComponentAdded(bool added)
{
if (m_isComponentAdded == added) {
return;
}
m_isComponentAdded = added;
emit componentAddChanged(added);
}
bool KeyComponentWidget::componentAdded() const
{
return m_isComponentAdded;
}
void KeyComponentWidget::changeVisiblePage(KeyComponentWidget::Page page)
{
m_previousPage = static_cast<Page>(m_ui->stackedWidget->currentIndex());
m_ui->stackedWidget->setCurrentIndex(page);
}
KeyComponentWidget::Page KeyComponentWidget::visiblePage() const
{
return static_cast<Page>(m_ui->stackedWidget->currentIndex());
}
void KeyComponentWidget::updateComponentName(const QString& name)
{
m_ui->groupBox->setTitle(name);
m_ui->addButton->setText(tr("Add %1", "Add a key component").arg(name));
m_ui->changeButton->setText(tr("Change %1", "Change a key component").arg(name));
m_ui->removeButton->setText(tr("Remove %1", "Remove a key component").arg(name));
m_ui->changeOrRemoveLabel->setText(
tr("%1 set, click to change or remove", "Change or remove a key component").arg(name));
}
void KeyComponentWidget::updateComponentDescription(const QString& description)
{
m_ui->componentDescription->setText(description);
}
void KeyComponentWidget::updateAddStatus(bool added)
{
if (added) {
m_ui->stackedWidget->setCurrentIndex(Page::LeaveOrRemove);
} else {
m_ui->stackedWidget->setCurrentIndex(Page::AddNew);
}
}
void KeyComponentWidget::doAdd()
{
changeVisiblePage(Page::Edit);
}
void KeyComponentWidget::doEdit()
{
changeVisiblePage(Page::Edit);
}
void KeyComponentWidget::doRemove()
{
changeVisiblePage(Page::AddNew);
}
void KeyComponentWidget::cancelEdit()
{
m_ui->stackedWidget->setCurrentIndex(m_previousPage);
emit editCanceled();
}
void KeyComponentWidget::showEvent(QShowEvent* event)
{
resetComponentEditWidget();
QWidget::showEvent(event);
}
void KeyComponentWidget::resetComponentEditWidget()
{
if (!m_componentWidget || static_cast<Page>(m_ui->stackedWidget->currentIndex()) == Page::Edit) {
if (m_componentWidget) {
delete m_componentWidget;
}
m_componentWidget = componentEditWidget();
m_ui->componentWidgetLayout->addWidget(m_componentWidget);
initComponentEditWidget(m_componentWidget);
}
QTimer::singleShot(0, this, SLOT(updateSize()));
}
void KeyComponentWidget::updateSize()
{
for (int i = 0; i < m_ui->stackedWidget->count(); ++i) {
if (m_ui->stackedWidget->currentIndex() == i) {
m_ui->stackedWidget->widget(i)->setSizePolicy(
m_ui->stackedWidget->widget(i)->sizePolicy().horizontalPolicy(), QSizePolicy::Preferred);
} else {
m_ui->stackedWidget->widget(i)->setSizePolicy(
m_ui->stackedWidget->widget(i)->sizePolicy().horizontalPolicy(), QSizePolicy::Ignored);
}
}
}

View file

@ -0,0 +1,137 @@
/*
* Copyright (C) 2018 KeePassXC Team <team@keepassxc.org>
*
* This program 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 2 or (at your option)
* version 3 of the License.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef KEEPASSXC_KEYCOMPONENTWIDGET_H
#define KEEPASSXC_KEYCOMPONENTWIDGET_H
#include <QPointer>
#include <QScopedPointer>
#include <QWidget>
namespace Ui
{
class KeyComponentWidget;
}
class CompositeKey;
class QStackedWidget;
class KeyComponentWidget : public QWidget
{
Q_OBJECT
// clang-format off
Q_PROPERTY(QString componentName READ m_componentName READ componentName
WRITE setComponentName NOTIFY nameChanged)
Q_PROPERTY(QString componentDescription READ m_componentDescription READ componentDescription
WRITE setComponentDescription NOTIFY descriptionChanged)
Q_PROPERTY(bool componentAdded READ m_isComponentAdded READ componentAdded
WRITE setComponentAdded NOTIFY componentAddChanged)
// clang-format on
public:
enum Page
{
AddNew = 0,
Edit = 1,
LeaveOrRemove = 2
};
explicit KeyComponentWidget(QWidget* parent = nullptr);
explicit KeyComponentWidget(const QString& name, QWidget* parent = nullptr);
Q_DISABLE_COPY(KeyComponentWidget);
~KeyComponentWidget() override;
/**
* Add the new key component to the given \link CompositeKey.
* A caller should always check first with \link validate() if
* the new key data is actually valid before adding it to a CompositeKey.
*
* @param key CompositeKey to add new key to
* @return true if added successfully
*/
virtual bool addToCompositeKey(QSharedPointer<CompositeKey> key) = 0;
/**
* Validate key component data to check if key component
* may be added to a CompositeKey.
*
* @param errorMessage error message in case data is not valid
* @return true if data is valid
*/
virtual bool validate(QString& errorMessage) const = 0;
void setComponentName(const QString& name);
QString componentName() const;
void setComponentDescription(const QString& name);
QString componentDescription() const;
void setComponentAdded(bool added);
bool componentAdded() const;
void changeVisiblePage(Page page);
Page visiblePage() const;
protected:
/**
* Construct and return an instance of the key component edit widget
* which is to be inserted into the component management UI.
* Since previous widgets will be destroyed, every successive call to
* this function must return a new widget.
*
* @return edit widget instance
*/
virtual QWidget* componentEditWidget() = 0;
/**
* Initialize the key component widget created by \link componentEditWidget().
* This method is called every time the component edit widget is shown.
*
* @param widget pointer to the widget
*/
virtual void initComponentEditWidget(QWidget* widget) = 0;
signals:
void nameChanged(const QString& newName);
void descriptionChanged(const QString& newDescription);
void componentAddChanged(bool added);
void componentAddRequested();
void componentEditRequested();
void editCanceled();
void componentRemovalRequested();
protected:
void showEvent(QShowEvent* event) override;
private slots:
void updateComponentName(const QString& name);
void updateComponentDescription(const QString& decription);
void updateAddStatus(bool added);
void doAdd();
void doEdit();
void doRemove();
void cancelEdit();
void resetComponentEditWidget();
void updateSize();
private:
bool m_isComponentAdded = false;
Page m_previousPage = Page::AddNew;
QString m_componentName;
QString m_componentDescription;
QPointer<QWidget> m_componentWidget;
const QScopedPointer<Ui::KeyComponentWidget> m_ui;
};
#endif // KEEPASSXC_KEYCOMPONENTWIDGET_H

View file

@ -0,0 +1,226 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>KeyComponentWidget</class>
<widget class="QWidget" name="KeyComponentWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>354</width>
<height>106</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">QGroupBox { font-weight: bold; }</string>
</property>
<property name="title">
<string>Key Component</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<property name="spacing">
<number>15</number>
</property>
<item>
<widget class="QStackedWidget" name="stackedWidget">
<property name="currentIndex">
<number>1</number>
</property>
<widget class="QWidget" name="addPage">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>10</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="componentDescription">
<property name="text">
<string>Key Component Description</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse</set>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="addButton">
<property name="text">
<string notr="true">Add Key Component</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="editPage">
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,0">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QWidget" name="componentWidgetContainer" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="componentWidgetLayout">
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="cancelButton">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="changeOrRemovePage">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="spacing">
<number>10</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="changeOrRemoveLabel">
<property name="text">
<string>Key Component set, click to change or remove</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="changeButton">
<property name="text">
<string notr="true">Change Key Component</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="removeButton">
<property name="text">
<string notr="true">Remove Key Component</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View file

@ -0,0 +1,148 @@
/*
* Copyright (C) 2018 KeePassXC Team <team@keepassxc.org>
*
* This program 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 2 or (at your option)
* version 3 of the License.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "KeyFileEditWidget.h"
#include "ui_KeyFileEditWidget.h"
#include <gui/dbsettings/DatabaseSettingsWidget.h>
#include "gui/FileDialog.h"
#include "gui/MainWindow.h"
#include "gui/MessageBox.h"
#include "keys/CompositeKey.h"
#include "keys/FileKey.h"
KeyFileEditWidget::KeyFileEditWidget(DatabaseSettingsWidget* parent)
: KeyComponentWidget(parent)
, m_compUi(new Ui::KeyFileEditWidget())
, m_parent(parent)
{
setComponentName(tr("Key File"));
setComponentDescription(tr("<p>You can add a key file containing random bytes for additional security.</p>"
"<p>You must keep it secret and never lose it or you will be locked out!</p>"));
}
KeyFileEditWidget::~KeyFileEditWidget()
{
}
bool KeyFileEditWidget::addToCompositeKey(QSharedPointer<CompositeKey> key)
{
auto fileKey = QSharedPointer<FileKey>::create();
QString fileKeyName = m_compUi->keyFileCombo->currentText();
if (!fileKey->load(fileKeyName, nullptr)) {
return false;
}
if (fileKey->type() != FileKey::Hashed) {
QMessageBox::warning(getMainWindow(),
tr("Legacy key file format"),
tr("You are using a legacy key file format which may become\n"
"unsupported in the future.\n\n"
"Generate a new key file in the database security settings."),
QMessageBox::Ok);
}
key->addKey(fileKey);
return true;
}
bool KeyFileEditWidget::validate(QString& errorMessage) const
{
FileKey fileKey;
QString fileKeyError;
QString fileKeyName = m_compUi->keyFileCombo->currentText();
if (!fileKey.load(fileKeyName, &fileKeyError)) {
errorMessage = tr("Error loading the key file '%1'\nMessage: %2").arg(fileKeyName, fileKeyError);
return false;
}
return true;
}
QWidget* KeyFileEditWidget::componentEditWidget()
{
m_compEditWidget = new QWidget();
m_compUi->setupUi(m_compEditWidget);
connect(m_compUi->createKeyFileButton, SIGNAL(clicked()), SLOT(createKeyFile()));
connect(m_compUi->browseKeyFileButton, SIGNAL(clicked()), SLOT(browseKeyFile()));
return m_compEditWidget;
}
void KeyFileEditWidget::initComponentEditWidget(QWidget* widget)
{
Q_UNUSED(widget);
Q_ASSERT(m_compEditWidget);
m_compUi->keyFileCombo->setFocus();
}
void KeyFileEditWidget::createKeyFile()
{
Q_ASSERT(m_compEditWidget);
if (!m_compEditWidget) {
return;
}
QString filters = QString("%1 (*.key);;%2 (*)").arg(tr("Key files"), tr("All files"));
QString fileName = fileDialog()->getSaveFileName(this, tr("Create Key File..."), QString(), filters);
if (!fileName.isEmpty()) {
QString errorMsg;
bool created = FileKey::create(fileName, &errorMsg);
if (!created) {
MessageBox::critical(getMainWindow(),
tr("Error creating key file"),
tr("Unable to create key file: %1").arg(errorMsg),
QMessageBox::Button::Ok);
} else {
m_compUi->keyFileCombo->setEditText(fileName);
}
}
}
void KeyFileEditWidget::browseKeyFile()
{
Q_ASSERT(m_compEditWidget);
if (!m_compEditWidget) {
return;
}
QString filters = QString("%1 (*.key);;%2 (*)").arg(tr("Key files"), tr("All files"));
QString fileName = fileDialog()->getOpenFileName(this, tr("Select a key file"), QString(), filters);
if (QFileInfo(fileName).canonicalFilePath() == m_parent->getDatabase()->canonicalFilePath()) {
MessageBox::critical(getMainWindow(),
tr("Invalid Key File"),
tr("You cannot use the current database as its own keyfile. Please choose a different "
"file or generate a new key file."));
return;
} else if (fileName.endsWith(".kdbx", Qt::CaseInsensitive)) {
auto response =
MessageBox::warning(getMainWindow(),
tr("Suspicious Key File"),
tr("The chosen key file looks like a password database file. A key file must be a "
"static file that never changes or you will lose access to your database "
"forever.\nAre you sure you want to continue with this file?"),
MessageBox::Continue | MessageBox::Cancel,
MessageBox::Cancel);
if (response != MessageBox::Continue) {
return;
}
}
if (!fileName.isEmpty()) {
m_compUi->keyFileCombo->setEditText(fileName);
}
}

View file

@ -0,0 +1,57 @@
/*
* Copyright (C) 2018 KeePassXC Team <team@keepassxc.org>
*
* This program 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 2 or (at your option)
* version 3 of the License.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef KEEPASSXC_KEYFILEEDITWIDGET_H
#define KEEPASSXC_KEYFILEEDITWIDGET_H
#include "KeyComponentWidget.h"
#include <QPointer>
namespace Ui
{
class KeyFileEditWidget;
}
class DatabaseSettingsWidget;
class KeyFileEditWidget : public KeyComponentWidget
{
Q_OBJECT
public:
explicit KeyFileEditWidget(DatabaseSettingsWidget* parent);
Q_DISABLE_COPY(KeyFileEditWidget);
~KeyFileEditWidget() override;
bool addToCompositeKey(QSharedPointer<CompositeKey> key) override;
bool validate(QString& errorMessage) const override;
protected:
QWidget* componentEditWidget() override;
void initComponentEditWidget(QWidget* widget) override;
private slots:
void createKeyFile();
void browseKeyFile();
private:
const QScopedPointer<Ui::KeyFileEditWidget> m_compUi;
QPointer<QWidget> m_compEditWidget;
const QPointer<DatabaseSettingsWidget> m_parent;
};
#endif // KEEPASSXC_KEYFILEEDITWIDGET_H

View file

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>KeyFileEditWidget</class>
<widget class="QWidget" name="KeyFileEditWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>370</width>
<height>76</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QComboBox" name="keyFileCombo">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="accessibleName">
<string>Key file selection</string>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="browseKeyFileButton">
<property name="accessibleName">
<string>Browse for key file</string>
</property>
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="createKeyFileButton">
<property name="accessibleName">
<string>Generate a new key file</string>
</property>
<property name="text">
<string>Generate</string>
</property>
</widget>
</item>
<item row="2" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="text">
<string>Note: Do not use a file that may change as that will prevent you from unlocking your database!</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View file

@ -0,0 +1,114 @@
/*
* Copyright (C) 2018 KeePassXC Team <team@keepassxc.org>
*
* This program 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 2 or (at your option)
* version 3 of the License.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "PasswordEditWidget.h"
#include "ui_PasswordEditWidget.h"
#include "core/Resources.h"
#include "gui/PasswordGeneratorWidget.h"
#include "keys/CompositeKey.h"
#include "keys/PasswordKey.h"
#include <QDialog>
PasswordEditWidget::PasswordEditWidget(QWidget* parent)
: KeyComponentWidget(parent)
, m_compUi(new Ui::PasswordEditWidget())
{
setComponentName(tr("Password"));
setComponentDescription(tr("<p>A password is the primary method for securing your database.</p>"
"<p>Good passwords are long and unique. KeePassXC can generate one for you.</p>"));
}
PasswordEditWidget::~PasswordEditWidget()
{
}
bool PasswordEditWidget::addToCompositeKey(QSharedPointer<CompositeKey> key)
{
QString pw = m_compUi->enterPasswordEdit->text();
if (!pw.isEmpty()) {
key->addKey(QSharedPointer<PasswordKey>::create(pw));
return true;
}
return false;
}
/**
* @param visible changed password visibility state
*/
void PasswordEditWidget::setPasswordVisible(bool visible)
{
m_compUi->enterPasswordEdit->setShowPassword(visible);
}
/**
* @return password visibility state
*/
bool PasswordEditWidget::isPasswordVisible() const
{
return m_compUi->enterPasswordEdit->isPasswordVisible();
}
bool PasswordEditWidget::isEmpty() const
{
return (visiblePage() == Page::Edit) && m_compUi->enterPasswordEdit->text().isEmpty();
}
QWidget* PasswordEditWidget::componentEditWidget()
{
m_compEditWidget = new QWidget();
m_compUi->setupUi(m_compEditWidget);
m_compUi->enterPasswordEdit->enablePasswordGenerator();
m_compUi->enterPasswordEdit->setRepeatPartner(m_compUi->repeatPasswordEdit);
return m_compEditWidget;
}
void PasswordEditWidget::initComponentEditWidget(QWidget* widget)
{
Q_UNUSED(widget);
Q_ASSERT(m_compEditWidget);
m_compUi->enterPasswordEdit->setFocus();
}
void PasswordEditWidget::hideEvent(QHideEvent* event)
{
if (!isVisible() && m_compUi->enterPasswordEdit) {
m_compUi->enterPasswordEdit->setText("");
m_compUi->repeatPasswordEdit->setText("");
}
QWidget::hideEvent(event);
}
bool PasswordEditWidget::validate(QString& errorMessage) const
{
if (m_compUi->enterPasswordEdit->text() != m_compUi->repeatPasswordEdit->text()) {
errorMessage = tr("Passwords do not match.");
return false;
}
return true;
}
void PasswordEditWidget::setPassword(const QString& password)
{
Q_ASSERT(m_compEditWidget);
m_compUi->enterPasswordEdit->setText(password);
m_compUi->repeatPasswordEdit->setText(password);
}

View file

@ -0,0 +1,57 @@
/*
* Copyright (C) 2018 KeePassXC Team <team@keepassxc.org>
*
* This program 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 2 or (at your option)
* version 3 of the License.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef KEEPASSXC_PASSWORDEDITWIDGET_H
#define KEEPASSXC_PASSWORDEDITWIDGET_H
#include "KeyComponentWidget.h"
#include <QPointer>
namespace Ui
{
class PasswordEditWidget;
}
class PasswordEditWidget : public KeyComponentWidget
{
Q_OBJECT
public:
explicit PasswordEditWidget(QWidget* parent = nullptr);
Q_DISABLE_COPY(PasswordEditWidget);
~PasswordEditWidget() override;
bool addToCompositeKey(QSharedPointer<CompositeKey> key) override;
void setPasswordVisible(bool visible);
bool isPasswordVisible() const;
bool isEmpty() const;
bool validate(QString& errorMessage) const override;
protected:
QWidget* componentEditWidget() override;
void initComponentEditWidget(QWidget* widget) override;
void hideEvent(QHideEvent* event) override;
private slots:
void setPassword(const QString& password);
private:
const QScopedPointer<Ui::PasswordEditWidget> m_compUi;
QPointer<QWidget> m_compEditWidget;
};
#endif // KEEPASSXC_PASSWORDEDITWIDGET_H

View file

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PasswordEditWidget</class>
<widget class="QWidget" name="PasswordEditWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>571</width>
<height>78</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="enterPasswordLabel">
<property name="text">
<string>Enter password:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="PasswordEdit" name="enterPasswordEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>300</width>
<height>0</height>
</size>
</property>
<property name="accessibleName">
<string>Password field</string>
</property>
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="repeatPasswordLabel">
<property name="text">
<string>Confirm password:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="PasswordEdit" name="repeatPasswordEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>300</width>
<height>0</height>
</size>
</property>
<property name="accessibleName">
<string>Repeat password field</string>
</property>
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>PasswordEdit</class>
<extends>QLineEdit</extends>
<header>gui/PasswordEdit.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>enterPasswordEdit</tabstop>
<tabstop>repeatPasswordEdit</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View file

@ -0,0 +1,141 @@
/*
* Copyright (C) 2018 KeePassXC Team <team@keepassxc.org>
*
* This program 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 2 or (at your option)
* version 3 of the License.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "YubiKeyEditWidget.h"
#include "ui_YubiKeyEditWidget.h"
#include "config-keepassx.h"
#include "core/AsyncTask.h"
#include "gui/MainWindow.h"
#include "gui/MessageBox.h"
#include "keys/CompositeKey.h"
#include "keys/YkChallengeResponseKey.h"
YubiKeyEditWidget::YubiKeyEditWidget(QWidget* parent)
: KeyComponentWidget(parent)
, m_compUi(new Ui::YubiKeyEditWidget())
{
setComponentName(tr("YubiKey Challenge-Response"));
setComponentDescription(
tr("<p>If you own a <a href=\"https://www.yubico.com/\">YubiKey</a>, you can use it "
"for additional security.</p><p>The YubiKey requires one of its slots to be programmed as "
"<a href=\"https://www.yubico.com/products/services-software/personalization-tools/challenge-response/\">"
"HMAC-SHA1 Challenge-Response</a>.</p>"));
connect(YubiKey::instance(), SIGNAL(detectComplete(bool)), SLOT(hardwareKeyResponse(bool)), Qt::QueuedConnection);
}
YubiKeyEditWidget::~YubiKeyEditWidget()
{
}
bool YubiKeyEditWidget::addToCompositeKey(QSharedPointer<CompositeKey> key)
{
if (!m_isDetected || !m_compEditWidget) {
return false;
}
int selectionIndex = m_compUi->comboChallengeResponse->currentIndex();
auto slot = m_compUi->comboChallengeResponse->itemData(selectionIndex).value<YubiKeySlot>();
key->addChallengeResponseKey(QSharedPointer<YkChallengeResponseKey>::create(slot));
return true;
}
bool YubiKeyEditWidget::validate(QString& errorMessage) const
{
if (!m_isDetected) {
errorMessage = tr("Could not find any hardware keys!");
return false;
}
// Perform a test challenge response
int selectionIndex = m_compUi->comboChallengeResponse->currentIndex();
auto slot = m_compUi->comboChallengeResponse->itemData(selectionIndex).value<YubiKeySlot>();
bool valid = AsyncTask::runAndWaitForFuture([&slot] { return YubiKey::instance()->testChallenge(slot); });
if (!valid) {
errorMessage = tr("Selected hardware key slot does not support challenge-response!");
}
return valid;
}
QWidget* YubiKeyEditWidget::componentEditWidget()
{
m_compEditWidget = new QWidget();
m_compUi->setupUi(m_compEditWidget);
QSizePolicy sp = m_compUi->yubikeyProgress->sizePolicy();
sp.setRetainSizeWhenHidden(true);
m_compUi->yubikeyProgress->setSizePolicy(sp);
m_compUi->yubikeyProgress->setVisible(false);
#ifdef WITH_XC_YUBIKEY
connect(m_compUi->buttonRedetectYubikey, SIGNAL(clicked()), SLOT(pollYubikey()));
pollYubikey();
#endif
return m_compEditWidget;
}
void YubiKeyEditWidget::initComponentEditWidget(QWidget* widget)
{
Q_UNUSED(widget);
Q_ASSERT(m_compEditWidget);
m_compUi->comboChallengeResponse->setFocus();
}
void YubiKeyEditWidget::pollYubikey()
{
#ifdef WITH_XC_YUBIKEY
if (!m_compEditWidget) {
return;
}
m_isDetected = false;
m_compUi->comboChallengeResponse->clear();
m_compUi->comboChallengeResponse->addItem(tr("Detecting hardware keys…"));
m_compUi->buttonRedetectYubikey->setEnabled(false);
m_compUi->comboChallengeResponse->setEnabled(false);
m_compUi->yubikeyProgress->setVisible(true);
YubiKey::instance()->findValidKeys();
#endif
}
void YubiKeyEditWidget::hardwareKeyResponse(bool found)
{
if (!m_compEditWidget) {
return;
}
m_compUi->comboChallengeResponse->clear();
m_compUi->buttonRedetectYubikey->setEnabled(true);
m_compUi->yubikeyProgress->setVisible(false);
if (!found) {
m_compUi->comboChallengeResponse->addItem(tr("No hardware keys detected"));
m_isDetected = false;
return;
}
for (auto& slot : YubiKey::instance()->foundKeys()) {
// add detected YubiKey to combo box and encode blocking mode in LSB, slot number in second LSB
m_compUi->comboChallengeResponse->addItem(YubiKey::instance()->getDisplayName(slot), QVariant::fromValue(slot));
}
m_isDetected = true;
m_compUi->comboChallengeResponse->setEnabled(true);
}

View file

@ -0,0 +1,57 @@
/*
* Copyright (C) 2018 KeePassXC Team <team@keepassxc.org>
*
* This program 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 2 or (at your option)
* version 3 of the License.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef KEEPASSXC_YUBIKEYEDITWIDGET_H
#define KEEPASSXC_YUBIKEYEDITWIDGET_H
#include "KeyComponentWidget.h"
#include <QPointer>
namespace Ui
{
class YubiKeyEditWidget;
}
class YkChallengeResponseKey;
class YubiKeyEditWidget : public KeyComponentWidget
{
Q_OBJECT
public:
explicit YubiKeyEditWidget(QWidget* parent = nullptr);
Q_DISABLE_COPY(YubiKeyEditWidget);
~YubiKeyEditWidget() override;
bool addToCompositeKey(QSharedPointer<CompositeKey> key) override;
bool validate(QString& errorMessage) const override;
protected:
QWidget* componentEditWidget() override;
void initComponentEditWidget(QWidget* widget) override;
private slots:
void hardwareKeyResponse(bool found);
void pollYubikey();
private:
const QScopedPointer<Ui::YubiKeyEditWidget> m_compUi;
QPointer<QWidget> m_compEditWidget;
bool m_isDetected = false;
};
#endif // KEEPASSXC_YUBIKEYEDITWIDGET_H

View file

@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>YubiKeyEditWidget</class>
<widget class="QWidget" name="YubiKeyEditWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>381</width>
<height>64</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QGridLayout" name="gridLayout_4">
<property name="verticalSpacing">
<number>0</number>
</property>
<item row="0" column="1">
<widget class="QPushButton" name="buttonRedetectYubikey">
<property name="accessibleName">
<string>Refresh hardware tokens</string>
</property>
<property name="text">
<string>Refresh</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QComboBox" name="comboChallengeResponse">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="accessibleName">
<string>Hardware key slot selection</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QProgressBar" name="yubikeyProgress">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>2</height>
</size>
</property>
<property name="maximum">
<number>0</number>
</property>
<property name="value">
<number>-1</number>
</property>
<property name="textVisible">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<tabstops>
<tabstop>comboChallengeResponse</tabstop>
<tabstop>buttonRedetectYubikey</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>