Merge pull request #373 from keepassxreboot/feature/new-password-generator

New Diceware passphrase generator
This commit is contained in:
Jonathan White 2017-04-09 12:36:56 -04:00 committed by GitHub
commit 5696178de4
12 changed files with 8509 additions and 413 deletions

View file

@ -15,6 +15,9 @@
add_subdirectory(translations) add_subdirectory(translations)
file(GLOB wordlists_files "wordlists/*.wordlist")
install(FILES ${wordlists_files} DESTINATION ${DATA_INSTALL_DIR}/wordlists)
file(GLOB DATABASE_ICONS icons/database/*.png) file(GLOB DATABASE_ICONS icons/database/*.png)
install(FILES ${DATABASE_ICONS} DESTINATION ${DATA_INSTALL_DIR}/icons/database) install(FILES ${DATABASE_ICONS} DESTINATION ${DATA_INSTALL_DIR}/icons/database)

File diff suppressed because it is too large Load diff

View file

@ -46,6 +46,7 @@ set(keepassx_SOURCES
core/ListDeleter.h core/ListDeleter.h
core/Metadata.cpp core/Metadata.cpp
core/PasswordGenerator.cpp core/PasswordGenerator.cpp
core/PassphraseGenerator.cpp
core/SignalMultiplexer.cpp core/SignalMultiplexer.cpp
core/TimeDelta.cpp core/TimeDelta.cpp
core/TimeInfo.cpp core/TimeInfo.cpp
@ -96,7 +97,6 @@ set(keepassx_SOURCES
gui/MessageWidget.cpp gui/MessageWidget.cpp
gui/PasswordEdit.cpp gui/PasswordEdit.cpp
gui/PasswordGeneratorWidget.cpp gui/PasswordGeneratorWidget.cpp
gui/PasswordComboBox.cpp
gui/SettingsWidget.cpp gui/SettingsWidget.cpp
gui/SearchWidget.cpp gui/SearchWidget.cpp
gui/SortFilterHideProxyModel.cpp gui/SortFilterHideProxyModel.cpp

View file

@ -0,0 +1,111 @@
/*
* Copyright (C) 2013 Felix Geyer <debfx@fobos.de>
*
* 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 "PassphraseGenerator.h"
#include <math.h>
#include <QFile>
#include <QTextStream>
#include "crypto/Random.h"
#include "core/FilePath.h"
PassphraseGenerator::PassphraseGenerator()
: m_wordCount(0)
, m_separator(' ')
{
const QString path = filePath()->dataPath("wordlists/eff_large.wordlist");
setWordList(path);
}
double PassphraseGenerator::calculateEntropy(QString passphrase)
{
Q_UNUSED(passphrase);
if (m_wordlist.size() == 0) {
return 0;
}
return log(m_wordlist.size()) / log(2.0) * m_wordCount;
}
void PassphraseGenerator::setWordCount(int wordCount)
{
if (wordCount > 0) {
m_wordCount = wordCount;
} else {
// safe default if something goes wrong
m_wordCount = 7;
}
}
void PassphraseGenerator::setWordList(QString path)
{
m_wordlist.clear();
QFile file(path);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qWarning("Couldn't load passphrase wordlist.");
return;
}
QTextStream in(&file);
while (!in.atEnd()) {
m_wordlist.append(in.readLine());
}
if (m_wordlist.size() < 4000) {
qWarning("Wordlist too short!");
return;
}
}
void PassphraseGenerator::setWordSeparator(QString separator) {
m_separator = separator;
}
QString PassphraseGenerator::generatePassphrase() const
{
Q_ASSERT(isValid());
// In case there was an error loading the wordlist
if(m_wordlist.length() == 0) {
return QString();
}
QStringList words;
for (int i = 0; i < m_wordCount; i++) {
int wordIndex = randomGen()->randomUInt(m_wordlist.length());
words.append(m_wordlist.at(wordIndex));
}
return words.join(m_separator);
}
bool PassphraseGenerator::isValid() const
{
if (m_wordCount == 0) {
return false;
}
if (m_wordlist.size() < 1000) {
return false;
}
return true;
}

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2013 Michael Curtis <michael@moltenmercury.org> * Copyright (C) 2013 Felix Geyer <debfx@fobos.de>
* Copyright (C) 2014 Felix Geyer <debfx@fobos.de>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -16,31 +15,32 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef KEEPASSX_PASSWORDCOMBOBOX_H #ifndef KEEPASSX_PASSPHRASEGENERATOR_H
#define KEEPASSX_PASSWORDCOMBOBOX_H #define KEEPASSX_PASSPHRASEGENERATOR_H
#include <QComboBox> #include <QFlags>
#include <QString>
#include <QVector>
class PasswordGenerator; class PassphraseGenerator
class PasswordComboBox : public QComboBox
{ {
Q_OBJECT
public: public:
explicit PasswordComboBox(QWidget* parent = nullptr); PassphraseGenerator();
~PasswordComboBox();
void setGenerator(PasswordGenerator* generator); double calculateEntropy(QString passphrase);
void setNumberAlternatives(int alternatives); void setWordCount(int wordCount);
void showPopup(); void setWordList(QString path);
void setWordSeparator(QString separator);
bool isValid() const;
public slots: QString generatePassphrase() const;
void setEcho(bool echo);
private: private:
PasswordGenerator* m_generator; int m_wordCount;
int m_alternatives; QString m_separator;
QVector<QString> m_wordlist;
Q_DISABLE_COPY(PassphraseGenerator)
}; };
#endif // KEEPASSX_PASSWORDCOMBOBOX_H #endif // KEEPASSX_PASSPHRASEGENERATOR_H

View file

@ -1,97 +0,0 @@
/*
* Copyright (C) 2013 Michael Curtis <michael@moltenmercury.org>
* Copyright (C) 2014 Felix Geyer <debfx@fobos.de>
*
* 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 "PasswordComboBox.h"
#include <QLineEdit>
#include "core/PasswordGenerator.h"
PasswordComboBox::PasswordComboBox(QWidget* parent)
: QComboBox(parent)
, m_generator(nullptr)
, m_alternatives(10)
{
setEditable(true);
setEcho(false);
}
PasswordComboBox::~PasswordComboBox()
{
}
void PasswordComboBox::setEcho(bool echo)
{
lineEdit()->setEchoMode(echo ? QLineEdit::Normal : QLineEdit::Password);
QString current = currentText();
if (echo) {
// add fake item to show visual indication that a popup is available
addItem("");
#ifdef Q_OS_MAC
// Qt on Mac OS doesn't seem to know the generic monospace family (tested with 4.8.6)
setStyleSheet("QComboBox { font-family: monospace,Menlo,Monaco; }");
#else
setStyleSheet("QComboBox { font-family: monospace,Courier New; }");
#endif
}
else {
// clear items so the combobox indicates that no popup menu is available
clear();
setStyleSheet("QComboBox { font-family: initial; }");
}
setEditText(current);
}
void PasswordComboBox::setGenerator(PasswordGenerator* generator)
{
m_generator = generator;
}
void PasswordComboBox::setNumberAlternatives(int alternatives)
{
m_alternatives = alternatives;
}
void PasswordComboBox::showPopup()
{
// no point in showing a bunch of hidden passwords
if (lineEdit()->echoMode() == QLineEdit::Password) {
hidePopup();
return;
}
// keep existing password as the first item in the popup
QString current = currentText();
clear();
addItem(current);
if (m_generator && m_generator->isValid()) {
for (int alternative = 0; alternative < m_alternatives; alternative++) {
QString password = m_generator->generatePassword();
addItem(password);
}
}
QComboBox::showPopup();
}

View file

@ -19,6 +19,7 @@
#include "ui_PasswordGeneratorWidget.h" #include "ui_PasswordGeneratorWidget.h"
#include <QLineEdit> #include <QLineEdit>
#include <QDir>
#include "core/Config.h" #include "core/Config.h"
#include "core/PasswordGenerator.h" #include "core/PasswordGenerator.h"
@ -27,7 +28,8 @@
PasswordGeneratorWidget::PasswordGeneratorWidget(QWidget* parent) PasswordGeneratorWidget::PasswordGeneratorWidget(QWidget* parent)
: QWidget(parent) : QWidget(parent)
, m_updatingSpinBox(false) , m_updatingSpinBox(false)
, m_generator(new PasswordGenerator()) , m_passwordGenerator(new PasswordGenerator())
, m_dicewareGenerator(new PassphraseGenerator())
, m_ui(new Ui::PasswordGeneratorWidget()) , m_ui(new Ui::PasswordGeneratorWidget())
{ {
m_ui->setupUi(this); m_ui->setupUi(this);
@ -38,12 +40,18 @@ PasswordGeneratorWidget::PasswordGeneratorWidget(QWidget* parent)
connect(m_ui->editNewPassword, SIGNAL(textChanged(QString)), SLOT(updatePasswordStrength(QString))); connect(m_ui->editNewPassword, SIGNAL(textChanged(QString)), SLOT(updatePasswordStrength(QString)));
connect(m_ui->togglePasswordButton, SIGNAL(toggled(bool)), SLOT(togglePasswordShown(bool))); connect(m_ui->togglePasswordButton, SIGNAL(toggled(bool)), SLOT(togglePasswordShown(bool)));
connect(m_ui->buttonApply, SIGNAL(clicked()), SLOT(applyPassword())); connect(m_ui->buttonApply, SIGNAL(clicked()), SLOT(applyPassword()));
connect(m_ui->buttonGenerate, SIGNAL(clicked()), SLOT(generatePassword())); connect(m_ui->buttonGenerate, SIGNAL(clicked()), SLOT(regeneratePassword()));
connect(m_ui->sliderLength, SIGNAL(valueChanged(int)), SLOT(sliderMoved())); connect(m_ui->sliderLength, SIGNAL(valueChanged(int)), SLOT(passwordSliderMoved()));
connect(m_ui->spinBoxLength, SIGNAL(valueChanged(int)), SLOT(spinBoxChanged())); connect(m_ui->spinBoxLength, SIGNAL(valueChanged(int)), SLOT(passwordSpinBoxChanged()));
connect(m_ui->sliderWordCount, SIGNAL(valueChanged(int)), SLOT(dicewareSliderMoved()));
connect(m_ui->spinBoxWordCount, SIGNAL(valueChanged(int)), SLOT(dicewareSpinBoxChanged()));
connect(m_ui->editWordSeparator, SIGNAL(textChanged(QString)), SLOT(updateGenerator()));
connect(m_ui->comboBoxWordList, SIGNAL(currentIndexChanged(int)), SLOT(updateGenerator()));
connect(m_ui->optionButtons, SIGNAL(buttonClicked(int)), SLOT(updateGenerator())); connect(m_ui->optionButtons, SIGNAL(buttonClicked(int)), SLOT(updateGenerator()));
connect(m_ui->tabWidget, SIGNAL(currentChanged(int)), SLOT(updateGenerator()));
// set font size of password quality and entropy labels dynamically to 80% of // set font size of password quality and entropy labels dynamically to 80% of
// the default font size, but make it no smaller than 8pt // the default font size, but make it no smaller than 8pt
@ -55,6 +63,20 @@ PasswordGeneratorWidget::PasswordGeneratorWidget(QWidget* parent)
m_ui->strengthLabel->setFont(defaultFont); m_ui->strengthLabel->setFont(defaultFont);
} }
// set default separator to Space
m_ui->editWordSeparator->setText(" ");
QDir path(filePath()->dataPath("wordlists/"));
QStringList files = path.entryList(QDir::Files);
m_ui->comboBoxWordList->addItems(files);
if (files.size() > 1) {
m_ui->comboBoxWordList->setVisible(true);
m_ui->labelWordList->setVisible(true);
} else {
m_ui->comboBoxWordList->setVisible(false);
m_ui->labelWordList->setVisible(false);
}
loadSettings(); loadSettings();
reset(); reset();
} }
@ -65,28 +87,42 @@ PasswordGeneratorWidget::~PasswordGeneratorWidget()
void PasswordGeneratorWidget::loadSettings() void PasswordGeneratorWidget::loadSettings()
{ {
// Password config
m_ui->checkBoxLower->setChecked(config()->get("generator/LowerCase", true).toBool()); m_ui->checkBoxLower->setChecked(config()->get("generator/LowerCase", true).toBool());
m_ui->checkBoxUpper->setChecked(config()->get("generator/UpperCase", true).toBool()); m_ui->checkBoxUpper->setChecked(config()->get("generator/UpperCase", true).toBool());
m_ui->checkBoxNumbers->setChecked(config()->get("generator/Numbers", true).toBool()); m_ui->checkBoxNumbers->setChecked(config()->get("generator/Numbers", true).toBool());
m_ui->checkBoxSpecialChars->setChecked(config()->get("generator/SpecialChars", false).toBool()); m_ui->checkBoxSpecialChars->setChecked(config()->get("generator/SpecialChars", false).toBool());
m_ui->checkBoxExcludeAlike->setChecked(config()->get("generator/ExcludeAlike", true).toBool()); m_ui->checkBoxExcludeAlike->setChecked(config()->get("generator/ExcludeAlike", true).toBool());
m_ui->checkBoxEnsureEvery->setChecked(config()->get("generator/EnsureEvery", true).toBool()); m_ui->checkBoxEnsureEvery->setChecked(config()->get("generator/EnsureEvery", true).toBool());
m_ui->spinBoxLength->setValue(config()->get("generator/Length", 16).toInt()); m_ui->spinBoxLength->setValue(config()->get("generator/Length", 16).toInt());
// Diceware config
m_ui->spinBoxWordCount->setValue(config()->get("generator/WordCount", 6).toInt());
m_ui->editWordSeparator->setText(config()->get("generator/WordSeparator", " ").toString());
m_ui->comboBoxWordList->setCurrentText(config()->get("generator/WordList", "eff_large.wordlist").toString());
// Password or diceware?
m_ui->tabWidget->setCurrentIndex(config()->get("generator/Type", 0).toInt());
} }
void PasswordGeneratorWidget::saveSettings() void PasswordGeneratorWidget::saveSettings()
{ {
// Password config
config()->set("generator/LowerCase", m_ui->checkBoxLower->isChecked()); config()->set("generator/LowerCase", m_ui->checkBoxLower->isChecked());
config()->set("generator/UpperCase", m_ui->checkBoxUpper->isChecked()); config()->set("generator/UpperCase", m_ui->checkBoxUpper->isChecked());
config()->set("generator/Numbers", m_ui->checkBoxNumbers->isChecked()); config()->set("generator/Numbers", m_ui->checkBoxNumbers->isChecked());
config()->set("generator/SpecialChars", m_ui->checkBoxSpecialChars->isChecked()); config()->set("generator/SpecialChars", m_ui->checkBoxSpecialChars->isChecked());
config()->set("generator/ExcludeAlike", m_ui->checkBoxExcludeAlike->isChecked()); config()->set("generator/ExcludeAlike", m_ui->checkBoxExcludeAlike->isChecked());
config()->set("generator/EnsureEvery", m_ui->checkBoxEnsureEvery->isChecked()); config()->set("generator/EnsureEvery", m_ui->checkBoxEnsureEvery->isChecked());
config()->set("generator/Length", m_ui->spinBoxLength->value()); config()->set("generator/Length", m_ui->spinBoxLength->value());
// Diceware config
config()->set("generator/WordCount", m_ui->spinBoxWordCount->value());
config()->set("generator/WordSeparator", m_ui->editWordSeparator->text());
config()->set("generator/WordList", m_ui->comboBoxWordList->currentText());
// Password or diceware?
config()->set("generator/Type", m_ui->tabWidget->currentIndex());
} }
void PasswordGeneratorWidget::reset() void PasswordGeneratorWidget::reset()
@ -109,10 +145,18 @@ void PasswordGeneratorWidget::setStandaloneMode(bool standalone)
void PasswordGeneratorWidget::regeneratePassword() void PasswordGeneratorWidget::regeneratePassword()
{ {
if (m_generator->isValid()) { if (m_ui->tabWidget->currentIndex() == Password) {
QString password = m_generator->generatePassword(); if (m_passwordGenerator->isValid()) {
m_ui->editNewPassword->setText(password); QString password = m_passwordGenerator->generatePassword();
updatePasswordStrength(password); m_ui->editNewPassword->setText(password);
updatePasswordStrength(password);
}
} else {
if (m_dicewareGenerator->isValid()) {
QString password = m_dicewareGenerator->generatePassphrase();
m_ui->editNewPassword->setText(password);
updatePasswordStrength(password);
}
} }
} }
@ -123,7 +167,13 @@ void PasswordGeneratorWidget::updateApplyEnabled(const QString& password)
void PasswordGeneratorWidget::updatePasswordStrength(const QString& password) void PasswordGeneratorWidget::updatePasswordStrength(const QString& password)
{ {
double entropy = m_generator->calculateEntropy(password); double entropy = 0.0;
if (m_ui->tabWidget->currentIndex() == Password) {
entropy = m_passwordGenerator->calculateEntropy(password);
} else {
entropy = m_dicewareGenerator->calculateEntropy(password);
}
m_ui->entropyLabel->setText(tr("Entropy: %1 bit").arg(QString::number(entropy, 'f', 2))); m_ui->entropyLabel->setText(tr("Entropy: %1 bit").arg(QString::number(entropy, 'f', 2)));
if (entropy > m_ui->entropyProgressBar->maximum()) { if (entropy > m_ui->entropyProgressBar->maximum()) {
@ -134,14 +184,6 @@ void PasswordGeneratorWidget::updatePasswordStrength(const QString& password)
colorStrengthIndicator(entropy); colorStrengthIndicator(entropy);
} }
void PasswordGeneratorWidget::generatePassword()
{
if (m_generator->isValid()) {
QString password = m_generator->generatePassword();
m_ui->editNewPassword->setText(password);
}
}
void PasswordGeneratorWidget::applyPassword() void PasswordGeneratorWidget::applyPassword()
{ {
saveSettings(); saveSettings();
@ -149,7 +191,7 @@ void PasswordGeneratorWidget::applyPassword()
emit dialogTerminated(); emit dialogTerminated();
} }
void PasswordGeneratorWidget::sliderMoved() void PasswordGeneratorWidget::passwordSliderMoved()
{ {
if (m_updatingSpinBox) { if (m_updatingSpinBox) {
return; return;
@ -160,7 +202,7 @@ void PasswordGeneratorWidget::sliderMoved()
updateGenerator(); updateGenerator();
} }
void PasswordGeneratorWidget::spinBoxChanged() void PasswordGeneratorWidget::passwordSpinBoxChanged()
{ {
if (m_updatingSpinBox) { if (m_updatingSpinBox) {
return; return;
@ -176,6 +218,20 @@ void PasswordGeneratorWidget::spinBoxChanged()
updateGenerator(); updateGenerator();
} }
void PasswordGeneratorWidget::dicewareSliderMoved()
{
m_ui->spinBoxWordCount->setValue(m_ui->sliderWordCount->value());
updateGenerator();
}
void PasswordGeneratorWidget::dicewareSpinBoxChanged()
{
m_ui->sliderWordCount->setValue(m_ui->spinBoxWordCount->value());
updateGenerator();
}
void PasswordGeneratorWidget::togglePasswordShown(bool showing) void PasswordGeneratorWidget::togglePasswordShown(bool showing)
{ {
m_ui->editNewPassword->setShowPassword(showing); m_ui->editNewPassword->setShowPassword(showing);
@ -196,13 +252,13 @@ void PasswordGeneratorWidget::colorStrengthIndicator(double entropy)
// Set the color and background based on entropy // Set the color and background based on entropy
// colors are taking from the KDE breeze palette // colors are taking from the KDE breeze palette
// <https://community.kde.org/KDE_Visual_Design_Group/HIG/Color> // <https://community.kde.org/KDE_Visual_Design_Group/HIG/Color>
if (entropy < 35) { if (entropy < 40) {
m_ui->entropyProgressBar->setStyleSheet(style.arg("#c0392b")); m_ui->entropyProgressBar->setStyleSheet(style.arg("#c0392b"));
m_ui->strengthLabel->setText(tr("Password Quality: %1").arg(tr("Poor"))); m_ui->strengthLabel->setText(tr("Password Quality: %1").arg(tr("Poor")));
} else if (entropy >= 35 && entropy < 55) { } else if (entropy >= 40 && entropy < 65) {
m_ui->entropyProgressBar->setStyleSheet(style.arg("#f39c1f")); m_ui->entropyProgressBar->setStyleSheet(style.arg("#f39c1f"));
m_ui->strengthLabel->setText(tr("Password Quality: %1").arg(tr("Weak"))); m_ui->strengthLabel->setText(tr("Password Quality: %1").arg(tr("Weak")));
} else if (entropy >= 55 && entropy < 100) { } else if (entropy >= 65 && entropy < 100) {
m_ui->entropyProgressBar->setStyleSheet(style.arg("#11d116")); m_ui->entropyProgressBar->setStyleSheet(style.arg("#11d116"));
m_ui->strengthLabel->setText(tr("Password Quality: %1").arg(tr("Good"))); m_ui->strengthLabel->setText(tr("Password Quality: %1").arg(tr("Good")));
} else { } else {
@ -251,44 +307,71 @@ PasswordGenerator::GeneratorFlags PasswordGeneratorWidget::generatorFlags()
void PasswordGeneratorWidget::updateGenerator() void PasswordGeneratorWidget::updateGenerator()
{ {
PasswordGenerator::CharClasses classes = charClasses(); if (m_ui->tabWidget->currentIndex() == Password) {
PasswordGenerator::GeneratorFlags flags = generatorFlags(); PasswordGenerator::CharClasses classes = charClasses();
PasswordGenerator::GeneratorFlags flags = generatorFlags();
int minLength = 0; int minLength = 0;
if (flags.testFlag(PasswordGenerator::CharFromEveryGroup)) { if (flags.testFlag(PasswordGenerator::CharFromEveryGroup)) {
if (classes.testFlag(PasswordGenerator::LowerLetters)) { if (classes.testFlag(PasswordGenerator::LowerLetters)) {
minLength++; minLength++;
}
if (classes.testFlag(PasswordGenerator::UpperLetters)) {
minLength++;
}
if (classes.testFlag(PasswordGenerator::Numbers)) {
minLength++;
}
if (classes.testFlag(PasswordGenerator::SpecialCharacters)) {
minLength++;
}
} }
if (classes.testFlag(PasswordGenerator::UpperLetters)) { minLength = qMax(minLength, 1);
minLength++;
if (m_ui->spinBoxLength->value() < minLength) {
m_updatingSpinBox = true;
m_ui->spinBoxLength->setValue(minLength);
m_ui->sliderLength->setValue(minLength);
m_updatingSpinBox = false;
} }
if (classes.testFlag(PasswordGenerator::Numbers)) {
minLength++; m_ui->spinBoxLength->setMinimum(minLength);
m_ui->sliderLength->setMinimum(minLength);
m_passwordGenerator->setLength(m_ui->spinBoxLength->value());
m_passwordGenerator->setCharClasses(classes);
m_passwordGenerator->setFlags(flags);
if (m_passwordGenerator->isValid()) {
m_ui->buttonGenerate->setEnabled(true);
} else {
m_ui->buttonGenerate->setEnabled(false);
} }
if (classes.testFlag(PasswordGenerator::SpecialCharacters)) {
minLength++;
}
}
minLength = qMax(minLength, 1);
if (m_ui->spinBoxLength->value() < minLength) {
m_updatingSpinBox = true;
m_ui->spinBoxLength->setValue(minLength);
m_ui->sliderLength->setValue(minLength);
m_updatingSpinBox = false;
}
m_ui->spinBoxLength->setMinimum(minLength);
m_ui->sliderLength->setMinimum(minLength);
m_generator->setLength(m_ui->spinBoxLength->value());
m_generator->setCharClasses(classes);
m_generator->setFlags(flags);
if (m_generator->isValid()) {
m_ui->buttonGenerate->setEnabled(true);
} else { } else {
m_ui->buttonGenerate->setEnabled(false); int minWordCount = 1;
if (m_ui->spinBoxWordCount->value() < minWordCount) {
m_updatingSpinBox = true;
m_ui->spinBoxWordCount->setValue(minWordCount);
m_ui->sliderWordCount->setValue(minWordCount);
m_updatingSpinBox = false;
}
m_ui->spinBoxWordCount->setMinimum(minWordCount);
m_ui->sliderWordCount->setMinimum(minWordCount);
m_dicewareGenerator->setWordCount(m_ui->spinBoxWordCount->value());
if (!m_ui->comboBoxWordList->currentText().isEmpty()) {
QString path = filePath()->dataPath("wordlists/" + m_ui->comboBoxWordList->currentText());
m_dicewareGenerator->setWordList(path);
}
m_dicewareGenerator->setWordSeparator(m_ui->editWordSeparator->text());
if (m_dicewareGenerator->isValid()) {
m_ui->buttonGenerate->setEnabled(true);
} else {
m_ui->buttonGenerate->setEnabled(false);
}
} }
regeneratePassword(); regeneratePassword();

View file

@ -23,24 +23,32 @@
#include <QLabel> #include <QLabel>
#include "core/PasswordGenerator.h" #include "core/PasswordGenerator.h"
#include "core/PassphraseGenerator.h"
namespace Ui { namespace Ui {
class PasswordGeneratorWidget; class PasswordGeneratorWidget;
} }
class PasswordGenerator; class PasswordGenerator;
class PassphraseGenerator;
class PasswordGeneratorWidget : public QWidget class PasswordGeneratorWidget : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
enum GeneratorTypes
{
Password = 0,
Diceware = 1
};
explicit PasswordGeneratorWidget(QWidget* parent = nullptr); explicit PasswordGeneratorWidget(QWidget* parent = nullptr);
~PasswordGeneratorWidget(); ~PasswordGeneratorWidget();
void loadSettings(); void loadSettings();
void saveSettings(); void saveSettings();
void reset(); void reset();
void setStandaloneMode(bool standalone); void setStandaloneMode(bool standalone);
public Q_SLOTS:
void regeneratePassword(); void regeneratePassword();
signals: signals:
@ -49,13 +57,14 @@ signals:
private slots: private slots:
void applyPassword(); void applyPassword();
void generatePassword();
void updateApplyEnabled(const QString& password); void updateApplyEnabled(const QString& password);
void updatePasswordStrength(const QString& password); void updatePasswordStrength(const QString& password);
void togglePasswordShown(bool hidden); void togglePasswordShown(bool hidden);
void sliderMoved(); void passwordSliderMoved();
void spinBoxChanged(); void passwordSpinBoxChanged();
void dicewareSliderMoved();
void dicewareSpinBoxChanged();
void colorStrengthIndicator(double entropy); void colorStrengthIndicator(double entropy);
void updateGenerator(); void updateGenerator();
@ -66,7 +75,8 @@ private:
PasswordGenerator::CharClasses charClasses(); PasswordGenerator::CharClasses charClasses();
PasswordGenerator::GeneratorFlags generatorFlags(); PasswordGenerator::GeneratorFlags generatorFlags();
const QScopedPointer<PasswordGenerator> m_generator; const QScopedPointer<PasswordGenerator> m_passwordGenerator;
const QScopedPointer<PassphraseGenerator> m_dicewareGenerator;
const QScopedPointer<Ui::PasswordGeneratorWidget> m_ui; const QScopedPointer<Ui::PasswordGeneratorWidget> m_ui;
}; };

View file

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>575</width> <width>575</width>
<height>284</height> <height>305</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -31,14 +31,14 @@
<property name="windowTitle"> <property name="windowTitle">
<string/> <string/>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,1"> <layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,0,0">
<property name="sizeConstraint"> <property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum> <enum>QLayout::SetMinimumSize</enum>
</property> </property>
<item> <item>
<layout class="QGridLayout" name="passwordFieldLayout"> <layout class="QGridLayout" name="passwordFieldLayout">
<property name="bottomMargin"> <property name="bottomMargin">
<number>10</number> <number>0</number>
</property> </property>
<property name="verticalSpacing"> <property name="verticalSpacing">
<number>0</number> <number>0</number>
@ -174,61 +174,6 @@ QProgressBar::chunk {
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0">
<widget class="QLabel" name="labelLength">
<property name="text">
<string>&amp;Length:</string>
</property>
<property name="buddy">
<cstring>spinBoxLength</cstring>
</property>
</widget>
</item>
<item row="3" column="1" colspan="2">
<layout class="QHBoxLayout" name="passwordLengthSliderLayout">
<property name="spacing">
<number>15</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<item>
<widget class="QSlider" name="sliderLength">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>128</number>
</property>
<property name="sliderPosition">
<number>20</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<number>8</number>
</property>
</widget>
</item>
<item alignment="Qt::AlignRight">
<widget class="QSpinBox" name="spinBoxLength">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>999</number>
</property>
<property name="value">
<number>20</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="2"> <item row="0" column="2">
<widget class="QToolButton" name="togglePasswordButton"> <widget class="QToolButton" name="togglePasswordButton">
<property name="checkable"> <property name="checkable">
@ -239,179 +184,390 @@ QProgressBar::chunk {
</layout> </layout>
</item> </item>
<item> <item>
<layout class="QHBoxLayout" name="optionsLayout"> <layout class="QHBoxLayout" name="horizontalLayout">
<item> <item>
<widget class="QGroupBox" name="groupBox"> <widget class="QTabWidget" name="tabWidget">
<property name="title"> <property name="sizePolicy">
<string>Character Types</string> <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <property name="minimumSize">
<item> <size>
<layout class="QHBoxLayout" name="alphabetLayout" stretch="0,0,0,0,1"> <width>0</width>
<item> <height>0</height>
<widget class="QToolButton" name="checkBoxUpper"> </size>
<property name="sizePolicy"> </property>
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding"> <property name="tabPosition">
<horstretch>0</horstretch> <enum>QTabWidget::North</enum>
<verstretch>0</verstretch> </property>
</sizepolicy> <property name="tabShape">
</property> <enum>QTabWidget::Rounded</enum>
<property name="minimumSize"> </property>
<size> <property name="currentIndex">
<width>0</width> <number>0</number>
<height>25</height> </property>
</size> <widget class="QWidget" name="passwordWidget">
</property> <attribute name="title">
<property name="focusPolicy"> <string>Password</string>
<enum>Qt::StrongFocus</enum> </attribute>
</property> <layout class="QGridLayout" name="gridLayout">
<property name="toolTip"> <item row="1" column="0">
<string>Upper Case Letters</string> <layout class="QHBoxLayout" name="optionsLayout">
</property> <item>
<property name="text"> <widget class="QGroupBox" name="groupBox">
<string notr="true">A-Z</string> <property name="title">
</property> <string>Character Types</string>
<property name="checkable"> </property>
<bool>true</bool> <layout class="QVBoxLayout" name="verticalLayout">
</property> <item>
<attribute name="buttonGroup"> <layout class="QHBoxLayout" name="alphabetLayout" stretch="0,0,0,0,1">
<string notr="true">optionButtons</string> <item>
</attribute> <widget class="QToolButton" name="checkBoxUpper">
</widget> <property name="sizePolicy">
</item> <sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
<item> <horstretch>0</horstretch>
<widget class="QToolButton" name="checkBoxLower"> <verstretch>0</verstretch>
<property name="sizePolicy"> </sizepolicy>
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding"> </property>
<horstretch>0</horstretch> <property name="minimumSize">
<verstretch>0</verstretch> <size>
</sizepolicy> <width>0</width>
</property> <height>25</height>
<property name="minimumSize"> </size>
<size> </property>
<width>0</width> <property name="focusPolicy">
<height>25</height> <enum>Qt::StrongFocus</enum>
</size> </property>
</property> <property name="toolTip">
<property name="focusPolicy"> <string>Upper Case Letters</string>
<enum>Qt::StrongFocus</enum> </property>
</property> <property name="text">
<property name="toolTip"> <string notr="true">A-Z</string>
<string>Lower Case Letters</string> </property>
</property> <property name="checkable">
<property name="text"> <bool>true</bool>
<string notr="true">a-z</string> </property>
</property> <attribute name="buttonGroup">
<property name="checkable"> <string notr="true">optionButtons</string>
<bool>true</bool> </attribute>
</property> </widget>
<attribute name="buttonGroup"> </item>
<string notr="true">optionButtons</string> <item>
</attribute> <widget class="QToolButton" name="checkBoxLower">
</widget> <property name="sizePolicy">
</item> <sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
<item> <horstretch>0</horstretch>
<widget class="QToolButton" name="checkBoxNumbers"> <verstretch>0</verstretch>
<property name="sizePolicy"> </sizepolicy>
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding"> </property>
<horstretch>0</horstretch> <property name="minimumSize">
<verstretch>0</verstretch> <size>
</sizepolicy> <width>0</width>
</property> <height>25</height>
<property name="minimumSize"> </size>
<size> </property>
<width>0</width> <property name="focusPolicy">
<height>25</height> <enum>Qt::StrongFocus</enum>
</size> </property>
</property> <property name="toolTip">
<property name="focusPolicy"> <string>Lower Case Letters</string>
<enum>Qt::StrongFocus</enum> </property>
</property> <property name="text">
<property name="toolTip"> <string notr="true">a-z</string>
<string>Numbers</string> </property>
</property> <property name="checkable">
<property name="text"> <bool>true</bool>
<string notr="true">0-9</string> </property>
</property> <attribute name="buttonGroup">
<property name="checkable"> <string notr="true">optionButtons</string>
<bool>true</bool> </attribute>
</property> </widget>
<attribute name="buttonGroup"> </item>
<string notr="true">optionButtons</string> <item>
</attribute> <widget class="QToolButton" name="checkBoxNumbers">
</widget> <property name="sizePolicy">
</item> <sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
<item> <horstretch>0</horstretch>
<widget class="QToolButton" name="checkBoxSpecialChars"> <verstretch>0</verstretch>
<property name="sizePolicy"> </sizepolicy>
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding"> </property>
<horstretch>0</horstretch> <property name="minimumSize">
<verstretch>0</verstretch> <size>
</sizepolicy> <width>0</width>
</property> <height>25</height>
<property name="minimumSize"> </size>
<size> </property>
<width>0</width> <property name="focusPolicy">
<height>25</height> <enum>Qt::StrongFocus</enum>
</size> </property>
</property> <property name="toolTip">
<property name="focusPolicy"> <string>Numbers</string>
<enum>Qt::StrongFocus</enum> </property>
</property> <property name="text">
<property name="toolTip"> <string notr="true">0-9</string>
<string>Special Characters</string> </property>
</property> <property name="checkable">
<property name="text"> <bool>true</bool>
<string notr="true">/*_&amp; ...</string> </property>
</property> <attribute name="buttonGroup">
<property name="checkable"> <string notr="true">optionButtons</string>
<bool>true</bool> </attribute>
</property> </widget>
<attribute name="buttonGroup"> </item>
<string notr="true">optionButtons</string> <item>
</attribute> <widget class="QToolButton" name="checkBoxSpecialChars">
</widget> <property name="sizePolicy">
</item> <sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
<item> <horstretch>0</horstretch>
<spacer name="horizontalSpacer"> <verstretch>0</verstretch>
<property name="orientation"> </sizepolicy>
<enum>Qt::Horizontal</enum> </property>
</property> <property name="minimumSize">
<property name="sizeHint" stdset="0"> <size>
<size> <width>0</width>
<width>40</width> <height>25</height>
<height>20</height> </size>
</size> </property>
</property> <property name="focusPolicy">
</spacer> <enum>Qt::StrongFocus</enum>
</item> </property>
</layout> <property name="toolTip">
</item> <string>Special Characters</string>
<item> </property>
<widget class="QCheckBox" name="checkBoxExcludeAlike"> <property name="text">
<property name="text"> <string notr="true">/*_&amp; ...</string>
<string>Exclude look-alike characters</string> </property>
</property> <property name="checkable">
<attribute name="buttonGroup"> <bool>true</bool>
<string notr="true">optionButtons</string> </property>
</attribute> <attribute name="buttonGroup">
</widget> <string notr="true">optionButtons</string>
</item> </attribute>
<item> </widget>
<widget class="QCheckBox" name="checkBoxEnsureEvery"> </item>
<property name="text"> <item>
<string>Pick characters from every group</string> <spacer name="horizontalSpacer">
</property> <property name="orientation">
<attribute name="buttonGroup"> <enum>Qt::Horizontal</enum>
<string notr="true">optionButtons</string> </property>
</attribute> <property name="sizeHint" stdset="0">
</widget> <size>
</item> <width>40</width>
</layout> <height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="checkBoxExcludeAlike">
<property name="text">
<string>Exclude look-alike characters</string>
</property>
<attribute name="buttonGroup">
<string notr="true">optionButtons</string>
</attribute>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxEnsureEvery">
<property name="text">
<string>Pick characters from every group</string>
</property>
<attribute name="buttonGroup">
<string notr="true">optionButtons</string>
</attribute>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item row="0" column="0">
<layout class="QHBoxLayout" name="passwordLengthSliderLayout">
<property name="spacing">
<number>15</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<item>
<widget class="QLabel" name="labelLength">
<property name="text">
<string>&amp;Length:</string>
</property>
<property name="buddy">
<cstring>spinBoxLength</cstring>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="sliderLength">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>128</number>
</property>
<property name="sliderPosition">
<number>20</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<number>8</number>
</property>
</widget>
</item>
<item alignment="Qt::AlignRight">
<widget class="QSpinBox" name="spinBoxLength">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>999</number>
</property>
<property name="value">
<number>20</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="dicewareWidget">
<attribute name="title">
<string>Passphrase</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0" alignment="Qt::AlignRight">
<widget class="QLabel" name="labelWordList">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Wordlist:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="comboBoxWordList">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="1" column="0" alignment="Qt::AlignRight">
<widget class="QLabel" name="labelWordCount">
<property name="text">
<string>Word Count:</string>
</property>
<property name="buddy">
<cstring>spinBoxLength</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
<item>
<widget class="QSlider" name="sliderWordCount">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>40</number>
</property>
<property name="value">
<number>6</number>
</property>
<property name="sliderPosition">
<number>6</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<number>8</number>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBoxWordCount">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>6</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0" alignment="Qt::AlignRight">
<widget class="QLabel" name="labelWordSeparator">
<property name="text">
<string>Word Separator:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="editWordSeparator">
<property name="text">
<string> </string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</widget> </widget>
</item> </item>
<item> <item>
<layout class="QVBoxLayout" name="globalButtonsLayout"> <layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item> <item>
<widget class="QPushButton" name="buttonGenerate"> <widget class="QPushButton" name="buttonGenerate">
<property name="text"> <property name="text">
@ -433,6 +589,9 @@ QProgressBar::chunk {
</item> </item>
</layout> </layout>
</item> </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4"/>
</item>
</layout> </layout>
</widget> </widget>
<customwidgets> <customwidgets>
@ -440,6 +599,7 @@ QProgressBar::chunk {
<class>PasswordEdit</class> <class>PasswordEdit</class>
<extends>QLineEdit</extends> <extends>QLineEdit</extends>
<header>gui/PasswordEdit.h</header> <header>gui/PasswordEdit.h</header>
<container>1</container>
</customwidget> </customwidget>
</customwidgets> </customwidgets>
<tabstops> <tabstops>
@ -452,9 +612,6 @@ QProgressBar::chunk {
<tabstop>checkBoxNumbers</tabstop> <tabstop>checkBoxNumbers</tabstop>
<tabstop>checkBoxSpecialChars</tabstop> <tabstop>checkBoxSpecialChars</tabstop>
<tabstop>checkBoxExcludeAlike</tabstop> <tabstop>checkBoxExcludeAlike</tabstop>
<tabstop>checkBoxEnsureEvery</tabstop>
<tabstop>buttonGenerate</tabstop>
<tabstop>buttonApply</tabstop>
</tabstops> </tabstops>
<resources/> <resources/>
<connections/> <connections/>

View file

@ -148,6 +148,12 @@
<verstretch>1</verstretch> <verstretch>1</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="minimumSize">
<size>
<width>0</width>
<height>100</height>
</size>
</property>
</widget> </widget>
</item> </item>
<item row="1" column="0" alignment="Qt::AlignRight"> <item row="1" column="0" alignment="Qt::AlignRight">
@ -186,6 +192,7 @@
<class>PasswordEdit</class> <class>PasswordEdit</class>
<extends>QLineEdit</extends> <extends>QLineEdit</extends>
<header>gui/PasswordEdit.h</header> <header>gui/PasswordEdit.h</header>
<container>1</container>
</customwidget> </customwidget>
</customwidgets> </customwidgets>
<tabstops> <tabstops>

View file

@ -26,6 +26,7 @@
#include <QPushButton> #include <QPushButton>
#include <QSpinBox> #include <QSpinBox>
#include <QPlainTextEdit> #include <QPlainTextEdit>
#include <QComboBox>
#include <QTemporaryFile> #include <QTemporaryFile>
#include <QTest> #include <QTest>
#include <QToolBar> #include <QToolBar>
@ -322,7 +323,7 @@ void TestGui::testAddEntry()
QTRY_COMPARE(entryView->model()->rowCount(), 4); QTRY_COMPARE(entryView->model()->rowCount(), 4);
} }
void TestGui::testEntryEntropy() void TestGui::testPasswordEntryEntropy()
{ {
QToolBar* toolBar = m_mainWindow->findChild<QToolBar*>("toolBar"); QToolBar* toolBar = m_mainWindow->findChild<QToolBar*>("toolBar");
@ -396,6 +397,50 @@ void TestGui::testEntryEntropy()
// We are done // We are done
} }
void TestGui::testDicewareEntryEntropy()
{
QToolBar* toolBar = m_mainWindow->findChild<QToolBar*>("toolBar");
// Find the new entry action
QAction* entryNewAction = m_mainWindow->findChild<QAction*>("actionEntryNew");
QVERIFY(entryNewAction->isEnabled());
// Find the button associated with the new entry action
QWidget* entryNewWidget = toolBar->widgetForAction(entryNewAction);
QVERIFY(entryNewWidget->isVisible());
QVERIFY(entryNewWidget->isEnabled());
// Click the new entry button and check that we enter edit mode
QTest::mouseClick(entryNewWidget, Qt::LeftButton);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::EditMode);
// Add entry "test" and confirm added
EditEntryWidget* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget");
QLineEdit* titleEdit = editEntryWidget->findChild<QLineEdit*>("titleEdit");
QTest::keyClicks(titleEdit, "test");
// Open the password generator
QToolButton* generatorButton = editEntryWidget->findChild<QToolButton*>("togglePasswordGeneratorButton");
QTest::mouseClick(generatorButton, Qt::LeftButton);
// Select Diceware
QTabWidget* tabWidget = editEntryWidget->findChild<QTabWidget*>("tabWidget");
QWidget* dicewareWidget = editEntryWidget->findChild<QWidget*>("dicewareWidget");
tabWidget->setCurrentWidget(dicewareWidget);
QComboBox* comboBoxWordList = dicewareWidget->findChild<QComboBox*>("comboBoxWordList");
comboBoxWordList->setCurrentText("eff_large.wordlist");
QSpinBox* spinBoxWordCount = dicewareWidget->findChild<QSpinBox*>("spinBoxWordCount");
spinBoxWordCount->setValue(6);
// Type in some password
QLabel* entropyLabel = editEntryWidget->findChild<QLabel*>("entropyLabel");
QLabel* strengthLabel = editEntryWidget->findChild<QLabel*>("strengthLabel");
QCOMPARE(entropyLabel->text(), QString("Entropy: 77.55 bit"));
QCOMPARE(strengthLabel->text(), QString("Password Quality: Good"));
}
void TestGui::testSearch() void TestGui::testSearch()
{ {
// Add canned entries for consistent testing // Add canned entries for consistent testing

View file

@ -44,7 +44,8 @@ private slots:
void testTabs(); void testTabs();
void testEditEntry(); void testEditEntry();
void testAddEntry(); void testAddEntry();
void testEntryEntropy(); void testPasswordEntryEntropy();
void testDicewareEntryEntropy();
void testSearch(); void testSearch();
void testDeleteEntry(); void testDeleteEntry();
void testCloneEntry(); void testCloneEntry();