Add some password-related feature (#92)

* Add Standalone Password Generator. Closes #18 
* Add an entropy meter for passwords. Closes #84
* Don't require password repeat when it is visible. Fixes #27
This commit is contained in:
TheZ3ro 2016-11-24 03:59:24 +01:00 committed by Jonathan White
parent 19a960856c
commit b2f3cc6903
28 changed files with 28401 additions and 195 deletions

View file

@ -174,13 +174,17 @@ endif()
qt5_wrap_ui(keepassx_SOURCES ${keepassx_FORMS})
add_library(zxcvbn STATIC zxcvbn/zxcvbn.cpp)
target_link_libraries(zxcvbn)
add_library(keepassx_core STATIC ${keepassx_SOURCES})
set_target_properties(keepassx_core PROPERTIES COMPILE_DEFINITIONS KEEPASSX_BUILDING_CORE)
target_link_libraries(keepassx_core Qt5::Core Qt5::Concurrent Qt5::Widgets Qt5::Network)
target_link_libraries(keepassx_core zxcvbn Qt5::Core Qt5::Concurrent Qt5::Widgets Qt5::Network)
add_executable(${PROGNAME} WIN32 MACOSX_BUNDLE ${keepassx_SOURCES_MAINEXE})
target_link_libraries(${PROGNAME}
keepassx_core
zxcvbn
${MHD_LIBRARIES}
Qt5::Core
Qt5::Concurrent

View file

@ -102,6 +102,7 @@ void Config::init(const QString& fileName)
m_defaults.insert("security/lockdatabaseidle", false);
m_defaults.insert("security/lockdatabaseidlesec", 10);
m_defaults.insert("security/lockdatabaseminimize", false);
m_defaults.insert("security/passwordsrepeat", false);
m_defaults.insert("security/passwordscleartext", false);
m_defaults.insert("security/autotypeask", true);
m_defaults.insert("GUI/Language", "system");

View file

@ -18,6 +18,7 @@
#include "PasswordGenerator.h"
#include "crypto/Random.h"
#include "zxcvbn/zxcvbn.h"
PasswordGenerator::PasswordGenerator()
: m_length(0)
@ -26,6 +27,11 @@ PasswordGenerator::PasswordGenerator()
{
}
double PasswordGenerator::calculateEntropy(QString password)
{
return ZxcvbnMatch(password.toLatin1(), 0, 0);
}
void PasswordGenerator::setLength(int length)
{
m_length = length;

View file

@ -46,6 +46,7 @@ public:
public:
PasswordGenerator();
double calculateEntropy(QString password);
void setLength(int length);
void setCharClasses(const CharClasses& classes);
void setFlags(const GeneratorFlags& flags);

View file

@ -69,24 +69,6 @@
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="PasswordEdit" name="editPassword">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="buttonTogglePassword">
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
@ -111,6 +93,24 @@
</item>
</layout>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="PasswordEdit" name="editPassword">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="buttonTogglePassword">
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>

View file

@ -39,6 +39,7 @@
#include "http/HttpSettings.h"
#include "http/OptionDialog.h"
#include "gui/SettingsWidget.h"
#include "gui/PasswordGeneratorWidget.h"
class HttpPlugin: public ISettingsPage
{
@ -168,6 +169,7 @@ MainWindow::MainWindow()
m_ui->actionGroupDelete->setIcon(filePath()->icon("actions", "group-delete", false));
m_ui->actionSettings->setIcon(filePath()->icon("actions", "configure"));
m_ui->actionPasswordGenerator->setIcon(filePath()->icon("actions", "password-generator", false));
m_ui->actionAbout->setIcon(filePath()->icon("actions", "help-about"));
@ -261,6 +263,8 @@ MainWindow::MainWindow()
SLOT(deleteGroup()));
connect(m_ui->actionSettings, SIGNAL(triggered()), SLOT(switchToSettings()));
connect(m_ui->actionPasswordGenerator, SIGNAL(toggled(bool)), SLOT(switchToPasswordGen(bool)));
connect(m_ui->passwordGeneratorWidget, SIGNAL(dialogTerminated()), SLOT(closePasswordGen()));
connect(m_ui->actionAbout, SIGNAL(triggered()), SLOT(showAboutDialog()));
@ -340,8 +344,9 @@ void MainWindow::minimizeWindow()
void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
{
bool inDatabaseTabWidget = (m_ui->stackedWidget->currentIndex() == 0);
bool inWelcomeWidget = (m_ui->stackedWidget->currentIndex() == 2);
int currentIndex = m_ui->stackedWidget->currentIndex();
bool inDatabaseTabWidget = (currentIndex == 0);
bool inWelcomeWidget = (currentIndex == 2);
if (inDatabaseTabWidget && m_ui->tabWidget->currentIndex() != -1) {
DatabaseWidget* dbWidget = m_ui->tabWidget->currentDatabaseWidget();
@ -453,6 +458,12 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
m_ui->actionRepairDatabase->setEnabled(inDatabaseTabWidgetOrWelcomeWidget);
m_ui->actionLockDatabases->setEnabled(m_ui->tabWidget->hasLockableDatabases());
if ((3 == currentIndex) != m_ui->actionPasswordGenerator->isChecked()) {
bool blocked = m_ui->actionPasswordGenerator->blockSignals(true);
m_ui->actionPasswordGenerator->toggle();
m_ui->actionPasswordGenerator->blockSignals(blocked);
}
}
void MainWindow::updateWindowTitle()
@ -501,6 +512,24 @@ void MainWindow::switchToSettings()
m_ui->stackedWidget->setCurrentIndex(1);
}
void MainWindow::switchToPasswordGen(bool enabled)
{
if (enabled == true) {
m_ui->passwordGeneratorWidget->loadSettings();
m_ui->passwordGeneratorWidget->regeneratePassword();
m_ui->passwordGeneratorWidget->setStandaloneMode(true);
m_ui->stackedWidget->setCurrentIndex(3);
} else {
m_ui->passwordGeneratorWidget->saveSettings();
switchToDatabases();
}
}
void MainWindow::closePasswordGen()
{
switchToPasswordGen(false);
}
void MainWindow::databaseStatusChanged(DatabaseWidget *)
{
updateTrayIcon();

View file

@ -54,6 +54,8 @@ private Q_SLOTS:
void showAboutDialog();
void switchToDatabases();
void switchToSettings();
void switchToPasswordGen(bool enabled);
void closePasswordGen();
void databaseStatusChanged(DatabaseWidget *dbWidget);
void databaseTabChanged(int tabIndex);
void openRecentDatabase(QAction* action);

View file

@ -87,6 +87,13 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="pagePasswordGenerator">
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="PasswordGeneratorWidget" name="passwordGeneratorWidget" native="true"/>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
@ -171,6 +178,7 @@
<string>Tools</string>
</property>
<addaction name="actionLockDatabases"/>
<addaction name="actionPasswordGenerator"/>
<addaction name="actionSettings"/>
</widget>
<widget class="QMenu" name="menuView">
@ -205,6 +213,7 @@
<addaction name="actionEntryCopyUsername"/>
<addaction name="actionEntryCopyPassword"/>
<addaction name="separator"/>
<addaction name="actionPasswordGenerator"/>
<addaction name="actionLockDatabases"/>
<addaction name="separator"/>
</widget>
@ -372,6 +381,14 @@
<string>&amp;Settings</string>
</property>
</action>
<action name="actionPasswordGenerator">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Password Generator</string>
</property>
</action>
<action name="actionEntryAutoType">
<property name="enabled">
<bool>false</bool>
@ -453,6 +470,12 @@
<header>gui/WelcomeWidget.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>PasswordGeneratorWidget</class>
<extends>QWidget</extends>
<header>gui/PasswordGeneratorWidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>

View file

@ -17,6 +17,10 @@
#include "PasswordEdit.h"
#include "core/Config.h"
#include <QFontDatabase>
const QColor PasswordEdit::CorrectSoFarColor = QColor(255, 205, 15);
const QColor PasswordEdit::ErrorColor = QColor(255, 125, 125);
@ -24,6 +28,13 @@ PasswordEdit::PasswordEdit(QWidget* parent)
: QLineEdit(parent)
, m_basePasswordEdit(nullptr)
{
setEchoMode(QLineEdit::Password);
updateStylesheet();
// set font to system monospace font and increase letter spacing
QFont passwordFont = QFontDatabase::systemFont(QFontDatabase::FixedFont);
passwordFont.setLetterSpacing(QFont::PercentageSpacing, 110);
setFont(passwordFont);
}
void PasswordEdit::enableVerifyMode(PasswordEdit* basePasswordEdit)
@ -31,6 +42,8 @@ void PasswordEdit::enableVerifyMode(PasswordEdit* basePasswordEdit)
m_basePasswordEdit = basePasswordEdit;
updateStylesheet();
connect(m_basePasswordEdit, SIGNAL(textChanged(QString)), SLOT(autocompletePassword(QString)));
connect(m_basePasswordEdit, SIGNAL(textChanged(QString)), SLOT(updateStylesheet()));
connect(this, SIGNAL(textChanged(QString)), SLOT(updateStylesheet()));
@ -40,6 +53,21 @@ void PasswordEdit::enableVerifyMode(PasswordEdit* basePasswordEdit)
void PasswordEdit::setShowPassword(bool show)
{
setEchoMode(show ? QLineEdit::Normal : QLineEdit::Password);
// if I have a parent, I'm the child
if (m_basePasswordEdit){
if (config()->get("security/passwordsrepeat").toBool()) {
setEnabled(!show);
setReadOnly(show);
setText(m_basePasswordEdit->text());
}
else {
// This fix a bug when the QLineEdit is disabled while switching config
if (isEnabled() == false) {
setEnabled(true);
setReadOnly(false);
}
}
}
updateStylesheet();
Q_EMIT showPasswordChanged(show);
}
@ -53,15 +81,6 @@ void PasswordEdit::updateStylesheet()
{
QString stylesheet("QLineEdit { ");
if (echoMode() == QLineEdit::Normal) {
#ifdef Q_OS_MAC
// Qt on Mac OS doesn't seem to know the generic monospace family (tested with 4.8.6)
stylesheet.append("font-family: monospace,Menlo,Monaco; ");
#else
stylesheet.append("font-family: monospace,Courier New; ");
#endif
}
if (m_basePasswordEdit && !passwordsEqual()) {
stylesheet.append("background: %1; ");
@ -76,3 +95,10 @@ void PasswordEdit::updateStylesheet()
stylesheet.append("}");
setStyleSheet(stylesheet);
}
void PasswordEdit::autocompletePassword(QString password)
{
if (config()->get("security/passwordsrepeat").toBool() && echoMode() == QLineEdit::Normal) {
setText(password);
}
}

View file

@ -39,6 +39,7 @@ Q_SIGNALS:
private Q_SLOTS:
void updateStylesheet();
void autocompletePassword(QString password);
private:
bool passwordsEqual() const;

View file

@ -34,18 +34,23 @@ PasswordGeneratorWidget::PasswordGeneratorWidget(QWidget* parent)
m_ui->togglePasswordButton->setIcon(filePath()->onOffIcon("actions", "password-show"));
connect(m_ui->editNewPassword->lineEdit(), SIGNAL(textChanged(QString)), SLOT(updateApplyEnabled(QString)));
connect(m_ui->togglePasswordButton, SIGNAL(toggled(bool)), m_ui->editNewPassword, SLOT(setEcho(bool)));
connect(m_ui->buttonApply, SIGNAL(clicked()), SLOT(emitNewPassword()));
connect(m_ui->buttonApply, SIGNAL(clicked()), SLOT(saveSettings()));
connect(m_ui->editNewPassword, SIGNAL(textChanged(QString)), SLOT(updateApplyEnabled(QString)));
connect(m_ui->editNewPassword, SIGNAL(textChanged(QString)), SLOT(updatePasswordStrength(QString)));
connect(m_ui->togglePasswordButton, SIGNAL(toggled(bool)), SLOT(togglePasswordShown(bool)));
connect(m_ui->buttonApply, SIGNAL(clicked()), SLOT(applyPassword()));
connect(m_ui->buttonGenerate, SIGNAL(clicked()), SLOT(generatePassword()));
connect(m_ui->sliderLength, SIGNAL(valueChanged(int)), SLOT(sliderMoved()));
connect(m_ui->spinBoxLength, SIGNAL(valueChanged(int)), SLOT(spinBoxChanged()));
connect(m_ui->optionButtons, SIGNAL(buttonClicked(int)), SLOT(updateGenerator()));
m_ui->editNewPassword->setGenerator(m_generator.data());
// set font size of password quality and entropy labels dynamically to 80% of the default font size
QFont defaultFont;
defaultFont.setPointSize(static_cast<int>(defaultFont.pointSize() * 0.8f));
m_ui->entropyLabel->setFont(defaultFont);
m_ui->strengthLabel->setFont(defaultFont);
loadSettings();
reset();
}
@ -82,17 +87,28 @@ void PasswordGeneratorWidget::saveSettings()
void PasswordGeneratorWidget::reset()
{
m_ui->editNewPassword->lineEdit()->setText("");
m_ui->togglePasswordButton->setChecked(config()->get("security/passwordscleartext").toBool());
m_ui->editNewPassword->setText("");
setStandaloneMode(false);
togglePasswordShown(config()->get("security/passwordscleartext").toBool());
updateGenerator();
}
void PasswordGeneratorWidget::setStandaloneMode(bool standalone)
{
if (standalone) {
m_ui->buttonApply->setText(tr("Close"));
togglePasswordShown(true);
} else {
m_ui->buttonApply->setText(tr("Apply"));
}
}
void PasswordGeneratorWidget::regeneratePassword()
{
if (m_generator->isValid()) {
QString password = m_generator->generatePassword();
m_ui->editNewPassword->setEditText(password);
m_ui->editNewPassword->setText(password);
updatePasswordStrength(password);
}
}
@ -101,9 +117,30 @@ void PasswordGeneratorWidget::updateApplyEnabled(const QString& password)
m_ui->buttonApply->setEnabled(!password.isEmpty());
}
void PasswordGeneratorWidget::emitNewPassword()
void PasswordGeneratorWidget::updatePasswordStrength(const QString& password)
{
Q_EMIT newPassword(m_ui->editNewPassword->lineEdit()->text());
double entropy = m_generator->calculateEntropy(password);
m_ui->entropyLabel->setText(tr("Entropy: %1 bit").arg(QString::number(entropy, 'f', 2)));
if (entropy > m_ui->entropyProgressBar->maximum()) {
entropy = m_ui->entropyProgressBar->maximum();
}
m_ui->entropyProgressBar->setValue(entropy);
colorStrengthIndicator(entropy);
}
void PasswordGeneratorWidget::generatePassword()
{
QString password = m_generator->generatePassword();
m_ui->editNewPassword->setText(password);
}
void PasswordGeneratorWidget::applyPassword()
{
saveSettings();
Q_EMIT appliedPassword(m_ui->editNewPassword->text());
Q_EMIT dialogTerminated();
}
void PasswordGeneratorWidget::sliderMoved()
@ -133,6 +170,41 @@ void PasswordGeneratorWidget::spinBoxChanged()
updateGenerator();
}
void PasswordGeneratorWidget::togglePasswordShown(bool showing)
{
m_ui->editNewPassword->setShowPassword(showing);
bool blockSignals = m_ui->togglePasswordButton->blockSignals(true);
m_ui->togglePasswordButton->setChecked(showing);
m_ui->togglePasswordButton->blockSignals(blockSignals);
}
void PasswordGeneratorWidget::colorStrengthIndicator(double entropy)
{
// Take the existing stylesheet and convert the text and background color to arguments
QString style = m_ui->entropyProgressBar->styleSheet();
QRegularExpression re("(QProgressBar::chunk\\s*\\{.*?background-color:)[^;]+;",
QRegularExpression::CaseInsensitiveOption |
QRegularExpression::DotMatchesEverythingOption);
style.replace(re, "\\1 %1;");
// Set the color and background based on entropy
// colors are taking from the KDE breeze palette
// <https://community.kde.org/KDE_Visual_Design_Group/HIG/Color>
if (entropy < 35) {
m_ui->entropyProgressBar->setStyleSheet(style.arg("#c0392b"));
m_ui->strengthLabel->setText(tr("Password Quality: %1").arg(tr("Poor")));
} else if (entropy >= 35 && entropy < 55) {
m_ui->entropyProgressBar->setStyleSheet(style.arg("#f39c1f"));
m_ui->strengthLabel->setText(tr("Password Quality: %1").arg(tr("Weak")));
} else if (entropy >= 55 && entropy < 100) {
m_ui->entropyProgressBar->setStyleSheet(style.arg("#11d116"));
m_ui->strengthLabel->setText(tr("Password Quality: %1").arg(tr("Good")));
} else {
m_ui->entropyProgressBar->setStyleSheet(style.arg("#27ae60"));
m_ui->strengthLabel->setText(tr("Password Quality: %1").arg(tr("Excellent")));
}
}
PasswordGenerator::CharClasses PasswordGeneratorWidget::charClasses()
{
PasswordGenerator::CharClasses classes;

View file

@ -20,6 +20,7 @@
#include <QWidget>
#include <QComboBox>
#include <QLabel>
#include "core/PasswordGenerator.h"
@ -37,19 +38,25 @@ public:
explicit PasswordGeneratorWidget(QWidget* parent = nullptr);
~PasswordGeneratorWidget();
void loadSettings();
void saveSettings();
void reset();
void setStandaloneMode(bool standalone);
void regeneratePassword();
Q_SIGNALS:
void newPassword(const QString& password);
void appliedPassword(const QString& password);
void dialogTerminated();
private Q_SLOTS:
void applyPassword();
void generatePassword();
void updateApplyEnabled(const QString& password);
void updatePasswordStrength(const QString& password);
void togglePasswordShown(bool hidden);
void emitNewPassword();
void saveSettings();
void sliderMoved();
void spinBoxChanged();
void colorStrengthIndicator(double entropy);
void updateGenerator();

View file

@ -6,60 +6,197 @@
<rect>
<x>0</x>
<y>0</y>
<width>434</width>
<height>250</height>
<width>500</width>
<height>278</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string/>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QGridLayout" name="gridLayout">
<layout class="QGridLayout" name="passwordFieldLayout">
<property name="bottomMargin">
<number>10</number>
</property>
<property name="verticalSpacing">
<number>0</number>
</property>
<item row="1" column="1">
<widget class="QProgressBar" name="entropyProgressBar">
<property name="minimumSize">
<size>
<width>50</width>
<height>5</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>5</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">QProgressBar {
border: none;
height: 2px;
font-size: 1px;
background-color: transparent;
padding: 0 1px;
}
QProgressBar::chunk {
background-color: #c0392b;
border-radius: 2px;
}</string>
</property>
<property name="maximum">
<number>200</number>
</property>
<property name="value">
<number>100</number>
</property>
<property name="textVisible">
<bool>false</bool>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="invertedAppearance">
<bool>false</bool>
</property>
<property name="textDirection">
<enum>QProgressBar::TopToBottom</enum>
</property>
<property name="format">
<string>%p%</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="labelNewPassword">
<property name="text">
<string>Password:</string>
</property>
<property name="buddy">
<cstring>editNewPassword</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="sizeConstraint">
<enum>QLayout::SetNoConstraint</enum>
</property>
<item row="2" column="1">
<layout class="QHBoxLayout" name="passwordStrengthTextLayout">
<item>
<widget class="PasswordComboBox" name="editNewPassword">
<property name="editable">
<bool>true</bool>
<widget class="QLabel" name="strengthLabel">
<property name="minimumSize">
<size>
<width>70</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>30</height>
</size>
</property>
<property name="font">
<font>
<pointsize>8</pointsize>
</font>
</property>
<property name="text">
<string>strength</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="margin">
<number>3</number>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="togglePasswordButton">
<property name="checkable">
<bool>true</bool>
<spacer name="horizontalSpacer_2">
<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="QLabel" name="entropyLabel">
<property name="minimumSize">
<size>
<width>70</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<pointsize>8</pointsize>
</font>
</property>
<property name="text">
<string>entropy</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing</set>
</property>
<property name="margin">
<number>3</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelLength">
<property name="text">
<string>Length:</string>
<item row="0" column="1">
<widget class="PasswordEdit" name="editNewPassword">
<property name="maxLength">
<number>999</number>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<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>64</number>
<number>128</number>
</property>
<property name="sliderPosition">
<number>20</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
@ -72,7 +209,7 @@
</property>
</widget>
</item>
<item>
<item alignment="Qt::AlignRight">
<widget class="QSpinBox" name="spinBoxLength">
<property name="minimum">
<number>1</number>
@ -80,30 +217,139 @@
<property name="maximum">
<number>999</number>
</property>
<property name="value">
<number>20</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="2">
<widget class="QToolButton" name="togglePasswordButton">
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Character Types</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<layout class="QHBoxLayout" name="optionsLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Character Types</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QToolButton" name="checkBoxUpper">
<property name="toolTip">
<string>Upper Case Letters</string>
</property>
<layout class="QHBoxLayout" name="alphabetLayout">
<item>
<widget class="QToolButton" name="checkBoxUpper">
<property name="minimumSize">
<size>
<width>0</width>
<height>26</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>Upper Case Letters</string>
</property>
<property name="text">
<string notr="true">A-Z</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">optionButtons</string>
</attribute>
</widget>
</item>
<item>
<widget class="QToolButton" name="checkBoxLower">
<property name="minimumSize">
<size>
<width>0</width>
<height>26</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>Lower Case Letters</string>
</property>
<property name="text">
<string notr="true">a-z</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">optionButtons</string>
</attribute>
</widget>
</item>
<item>
<widget class="QToolButton" name="checkBoxNumbers">
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>Numbers</string>
</property>
<property name="text">
<string notr="true">0-9</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">optionButtons</string>
</attribute>
</widget>
</item>
<item>
<widget class="QToolButton" name="checkBoxSpecialChars">
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>Special Characters</string>
</property>
<property name="text">
<string notr="true">/*_&amp; ...</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">optionButtons</string>
</attribute>
</widget>
</item>
<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>
</layout>
</item>
<item>
<widget class="QCheckBox" name="checkBoxExcludeAlike">
<property name="text">
<string notr="true">A-Z</string>
</property>
<property name="checkable">
<bool>true</bool>
<string>Exclude look-alike characters</string>
</property>
<attribute name="buttonGroup">
<string notr="true">optionButtons</string>
@ -111,115 +357,38 @@
</widget>
</item>
<item>
<widget class="QToolButton" name="checkBoxLower">
<property name="toolTip">
<string>Lower Case Letters</string>
</property>
<widget class="QCheckBox" name="checkBoxEnsureEvery">
<property name="text">
<string notr="true">a-z</string>
</property>
<property name="checkable">
<bool>true</bool>
<string>Pick characters from every group</string>
</property>
<attribute name="buttonGroup">
<string notr="true">optionButtons</string>
</attribute>
</widget>
</item>
<item>
<widget class="QToolButton" name="checkBoxNumbers">
<property name="toolTip">
<string>Numbers</string>
</property>
<property name="text">
<string notr="true">0-9</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">optionButtons</string>
</attribute>
</widget>
</item>
<item>
<widget class="QToolButton" name="checkBoxSpecialChars">
<property name="toolTip">
<string>Special Characters</string>
</property>
<property name="text">
<string notr="true">/*_&amp; ...</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">optionButtons</string>
</attribute>
</widget>
</item>
<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>
</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>Ensure that the password contains characters from every group</string>
</property>
<attribute name="buttonGroup">
<string notr="true">optionButtons</string>
</attribute>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonApply">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Accept</string>
</property>
</widget>
<layout class="QVBoxLayout" name="globalButtonsLayout">
<item>
<widget class="QPushButton" name="buttonGenerate">
<property name="text">
<string>Generate</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonApply">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Accept</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
@ -227,9 +396,9 @@
</widget>
<customwidgets>
<customwidget>
<class>PasswordComboBox</class>
<extends>QComboBox</extends>
<header location="global">gui/PasswordComboBox.h</header>
<class>PasswordEdit</class>
<extends>QLineEdit</extends>
<header>gui/PasswordEdit.h</header>
</customwidget>
</customwidgets>
<tabstops>
@ -243,6 +412,7 @@
<tabstop>checkBoxSpecialChars</tabstop>
<tabstop>checkBoxExcludeAlike</tabstop>
<tabstop>checkBoxEnsureEvery</tabstop>
<tabstop>buttonGenerate</tabstop>
<tabstop>buttonApply</tabstop>
</tabstops>
<resources/>

View file

@ -137,6 +137,7 @@ void SettingsWidget::loadSettings()
m_secUi->lockDatabaseMinimizeCheckBox->setChecked(config()->get("security/lockdatabaseminimize").toBool());
m_secUi->passwordCleartextCheckBox->setChecked(config()->get("security/passwordscleartext").toBool());
m_secUi->passwordRepeatCheckBox->setChecked(config()->get("security/passwordsrepeat").toBool());
m_secUi->autoTypeAskCheckBox->setChecked(config()->get("security/autotypeask").toBool());
@ -181,6 +182,7 @@ void SettingsWidget::saveSettings()
config()->set("security/lockdatabaseminimize", m_secUi->lockDatabaseMinimizeCheckBox->isChecked());
config()->set("security/passwordscleartext", m_secUi->passwordCleartextCheckBox->isChecked());
config()->set("security/passwordsrepeat", m_secUi->passwordRepeatCheckBox->isChecked());
config()->set("security/autotypeask", m_secUi->autoTypeAskCheckBox->isChecked());

View file

@ -72,6 +72,13 @@
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="passwordRepeatCheckBox">
<property name="text">
<string>Don't require password repeat when it is visible</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="autoTypeAskCheckBox">
<property name="text">
<string>Always ask before performing auto-type</string>

View file

@ -93,7 +93,7 @@ void EditEntryWidget::setupMain()
connect(m_mainUi->tooglePasswordGeneratorButton, SIGNAL(toggled(bool)), SLOT(togglePasswordGeneratorButton(bool)));
connect(m_mainUi->expireCheck, SIGNAL(toggled(bool)), m_mainUi->expireDatePicker, SLOT(setEnabled(bool)));
m_mainUi->passwordRepeatEdit->enableVerifyMode(m_mainUi->passwordEdit);
connect(m_mainUi->passwordGenerator, SIGNAL(newPassword(QString)), SLOT(setGeneratedPassword(QString)));
connect(m_mainUi->passwordGenerator, SIGNAL(appliedPassword(QString)), SLOT(setGeneratedPassword(QString)));
m_mainUi->expirePresets->setMenu(createPresetsMenu());
connect(m_mainUi->expirePresets->menu(), SIGNAL(triggered(QAction*)), this, SLOT(useExpiryPreset(QAction*)));

View file

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>372</width>
<height>301</height>
<height>364</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout">
@ -78,7 +78,7 @@
<item>
<widget class="QToolButton" name="tooglePasswordGeneratorButton">
<property name="text">
<string>Gen.</string>
<string>Generate</string>
</property>
<property name="checkable">
<bool>true</bool>

24872
src/zxcvbn/dict-src.h Normal file

File diff suppressed because it is too large Load diff

1772
src/zxcvbn/zxcvbn.cpp Normal file

File diff suppressed because it is too large Load diff

139
src/zxcvbn/zxcvbn.h Normal file
View file

@ -0,0 +1,139 @@
#ifndef ZXCVBN_H_F98183CE2A01_INCLUDED
#define ZXCVBN_H_F98183CE2A01_INCLUDED
/**********************************************************************************
* C implementation of the zxcvbn password strength estimation method.
* Copyright (c) 2015, Tony Evans
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
**********************************************************************************/
/* If this is defined, the dictiononary data is read from file. When undefined */
/* dictionary data is included in the source code. */
/*#define USE_DICT_FILE */
/* If this is defined, C++ builds which read dictionary data from file will use */
/* stdio FILE streams (and fopen,fread,fclose). When undefined, C++ builds will */
/* use std::ifstream to read dictionary data. Ignored for C builds (stdio FILE */
/* streams are always used). */
/*#define USE_FILE_IO */
#ifndef __cplusplus
/* C build. Use the standard malloc/free for heap memory */
#include <stdlib.h>
#define MallocFn(T,N) ((T *)malloc((N) * sizeof(T)))
#define FreeFn(P) free(P)
#else
/* C++ build. Use the new/delete operators for heap memory */
#define MallocFn(T,N) (new T[N])
#define FreeFn(P) (delete [] P)
#endif
/* Enum for the types of match returned in the Info arg to ZxcvbnMatch */
typedef enum
{
NON_MATCH, /* 0 */
BRUTE_MATCH, /* 1 */
DICTIONARY_MATCH, /* 2 */
DICT_LEET_MATCH, /* 3 */
USER_MATCH, /* 4 */
USER_LEET_MATCH, /* 5 */
REPEATS_MATCH, /* 6 */
SEQUENCE_MATCH, /* 7 */
SPATIAL_MATCH, /* 8 */
DATE_MATCH, /* 9 */
YEAR_MATCH, /* 10 */
MULTIPLE_MATCH = 32 /* Added to above to indicate matching part has been repeated */
} ZxcTypeMatch_t;
/* Linked list of information returned in the Info arg to ZxcvbnMatch */
struct ZxcMatch
{
int Begin; /* Char position of begining of match */
int Length; /* Number of chars in the match */
double Entrpy; /* The entropy of the match */
double MltEnpy; /* Entropy with additional allowance for multipart password */
ZxcTypeMatch_t Type; /* Type of match (Spatial/Dictionary/Order/Repeat) */
struct ZxcMatch *Next;
};
typedef struct ZxcMatch ZxcMatch_t;
#ifdef __cplusplus
extern "C" {
#endif
#ifdef USE_DICT_FILE
/**********************************************************************************
* Read the dictionnary data from the given file. Returns 1 if OK, 0 if error.
* Called once at program startup.
*/
int ZxcvbnInit(const char *);
/**********************************************************************************
* Free the dictionnary data after use. Called once at program shutdown.
*/
void ZxcvbnUnInit();
#else
/* As the dictionary data is included in the source, define these functions to do nothing. */
#define ZxcvbnInit(s) 1
#define ZxcvbnUnInit() do {} while(0)
#endif
/**********************************************************************************
* The main password matching function. May be called multiple times.
* The parameters are:
* Passwd The password to be tested. Null terminated string.
* UserDict User supplied dictionary words to be considered particulary bad. Passed
* as a pointer to array of string pointers, with null last entry (like
* the argv parameter to main()). May be null or point to empty array when
* there are no user dictionary words.
* Info The address of a pointer variable to receive information on the parts
* of the password. This parameter can be null if no information is wanted.
* The data should be freed by calling ZxcvbnFreeInfo().
*
* Returns the entropy of the password (in bits).
*/
double ZxcvbnMatch(const char *Passwd, const char *UserDict[], ZxcMatch_t **Info);
/**********************************************************************************
* Free the data returned in the Info parameter to ZxcvbnMatch().
*/
void ZxcvbnFreeInfo(ZxcMatch_t *Info);
#ifdef __cplusplus
}
#endif
#endif