diff --git a/src/browser/BrowserSettings.cpp b/src/browser/BrowserSettings.cpp index b49af7005..eb5d81d29 100644 --- a/src/browser/BrowserSettings.cpp +++ b/src/browser/BrowserSettings.cpp @@ -412,6 +412,16 @@ void BrowserSettings::setAdvancedMode(bool advancedMode) config()->set("generator/AdvancedMode", advancedMode); } +QString BrowserSettings::passwordAdditionalChars() +{ + return config()->get("generator/AdditionalChars", PasswordGenerator::DefaultAdditionalChars).toString(); +} + +void BrowserSettings::setPasswordAdditionalChars(const QString& chars) +{ + config()->set("generator/AdditionalChars", chars); +} + QString BrowserSettings::passwordExcludedChars() { return config()->get("generator/ExcludedChars", PasswordGenerator::DefaultExcludedChars).toString(); diff --git a/src/browser/BrowserSettings.h b/src/browser/BrowserSettings.h index 395455cbc..9340cd0a3 100644 --- a/src/browser/BrowserSettings.h +++ b/src/browser/BrowserSettings.h @@ -107,6 +107,8 @@ public: void setPasswordUseEASCII(bool useEASCII); bool advancedMode(); void setAdvancedMode(bool advancedMode); + QString passwordAdditionalChars(); + void setPasswordAdditionalChars(const QString& chars); QString passwordExcludedChars(); void setPasswordExcludedChars(const QString& chars); int passPhraseWordCount(); diff --git a/src/core/PasswordGenerator.cpp b/src/core/PasswordGenerator.cpp index ff271a453..efe647880 100644 --- a/src/core/PasswordGenerator.cpp +++ b/src/core/PasswordGenerator.cpp @@ -20,12 +20,14 @@ #include "crypto/Random.h" +const char* PasswordGenerator::DefaultAdditionalChars = ""; const char* PasswordGenerator::DefaultExcludedChars = ""; PasswordGenerator::PasswordGenerator() : m_length(0) , m_classes(nullptr) , m_flags(nullptr) + , m_additional(PasswordGenerator::DefaultAdditionalChars) , m_excluded(PasswordGenerator::DefaultExcludedChars) { } @@ -53,6 +55,11 @@ void PasswordGenerator::setFlags(const GeneratorFlags& flags) m_flags = flags; } +void PasswordGenerator::setAdditionalChars(const QString& chars) +{ + m_additional = chars; +} + void PasswordGenerator::setExcludedChars(const QString& chars) { m_excluded = chars; @@ -107,7 +114,7 @@ QString PasswordGenerator::generatePassword() const bool PasswordGenerator::isValid() const { - if (m_classes == 0) { + if (m_classes == 0 && m_additional.isEmpty()) { return false; } else if (m_length == 0) { return false; @@ -259,6 +266,15 @@ QVector PasswordGenerator::passwordGroups() const passwordGroups.append(group); } + if (!m_additional.isEmpty()) { + PasswordGroup group; + + for (auto ch : m_additional) { + group.append(ch); + } + + passwordGroups.append(group); + } // Loop over character groups and remove excluded characters from them; // remove empty groups diff --git a/src/core/PasswordGenerator.h b/src/core/PasswordGenerator.h index 55418b4ba..20681c233 100644 --- a/src/core/PasswordGenerator.h +++ b/src/core/PasswordGenerator.h @@ -60,6 +60,7 @@ public: void setLength(int length); void setCharClasses(const CharClasses& classes); void setFlags(const GeneratorFlags& flags); + void setAdditionalChars(const QString& chars); void setExcludedChars(const QString& chars); bool isValid() const; @@ -67,6 +68,7 @@ public: QString generatePassword() const; static const int DefaultLength = 16; + static const char* DefaultAdditionalChars; static const char* DefaultExcludedChars; static constexpr bool DefaultLower = (DefaultCharset & LowerLetters) != 0; static constexpr bool DefaultUpper = (DefaultCharset & UpperLetters) != 0; @@ -90,6 +92,7 @@ private: int m_length; CharClasses m_classes; GeneratorFlags m_flags; + QString m_additional; QString m_excluded; Q_DISABLE_COPY(PasswordGenerator) diff --git a/src/gui/PasswordGeneratorWidget.cpp b/src/gui/PasswordGeneratorWidget.cpp index 436124813..7ce45b1d1 100644 --- a/src/gui/PasswordGeneratorWidget.cpp +++ b/src/gui/PasswordGeneratorWidget.cpp @@ -48,6 +48,7 @@ PasswordGeneratorWidget::PasswordGeneratorWidget(QWidget* parent) connect(m_ui->editNewPassword, SIGNAL(textChanged(QString)), SLOT(updatePasswordStrength(QString))); connect(m_ui->buttonAdvancedMode, SIGNAL(toggled(bool)), SLOT(setAdvancedMode(bool))); connect(m_ui->buttonAddHex, SIGNAL(clicked()), SLOT(excludeHexChars())); + connect(m_ui->editAdditionalChars, SIGNAL(textChanged(QString)), SLOT(updateGenerator())); connect(m_ui->editExcludedChars, SIGNAL(textChanged(QString)), SLOT(updateGenerator())); connect(m_ui->buttonApply, SIGNAL(clicked()), SLOT(applyPassword())); connect(m_ui->buttonCopy, SIGNAL(clicked()), SLOT(copyPassword())); @@ -114,6 +115,8 @@ void PasswordGeneratorWidget::loadSettings() config()->get("generator/SpecialChars", PasswordGenerator::DefaultSpecial).toBool()); m_ui->checkBoxNumbersAdv->setChecked( config()->get("generator/Numbers", PasswordGenerator::DefaultNumbers).toBool()); + m_ui->editAdditionalChars->setText( + config()->get("generator/AdditionalChars", PasswordGenerator::DefaultAdditionalChars).toString()); m_ui->editExcludedChars->setText( config()->get("generator/ExcludedChars", PasswordGenerator::DefaultExcludedChars).toString()); @@ -315,6 +318,7 @@ void PasswordGeneratorWidget::setAdvancedMode(bool state) { if (state) { m_ui->simpleBar->hide(); + m_ui->advancedContainer->show(); m_ui->checkBoxUpperAdv->setChecked(m_ui->checkBoxUpper->isChecked()); m_ui->checkBoxLowerAdv->setChecked(m_ui->checkBoxLower->isChecked()); m_ui->checkBoxNumbersAdv->setChecked(m_ui->checkBoxNumbers->isChecked()); @@ -325,15 +329,9 @@ void PasswordGeneratorWidget::setAdvancedMode(bool state) m_ui->checkBoxDashes->setChecked(m_ui->checkBoxSpecialChars->isChecked()); m_ui->checkBoxLogograms->setChecked(m_ui->checkBoxSpecialChars->isChecked()); m_ui->checkBoxExtASCIIAdv->setChecked(m_ui->checkBoxExtASCII->isChecked()); - m_ui->advancedBar->show(); - m_ui->excludedChars->show(); - m_ui->checkBoxExcludeAlike->show(); - m_ui->checkBoxEnsureEvery->show(); } else { - m_ui->advancedBar->hide(); - m_ui->excludedChars->hide(); - m_ui->checkBoxExcludeAlike->hide(); - m_ui->checkBoxEnsureEvery->hide(); + m_ui->simpleBar->show(); + m_ui->advancedContainer->hide(); m_ui->checkBoxUpper->setChecked(m_ui->checkBoxUpperAdv->isChecked()); m_ui->checkBoxLower->setChecked(m_ui->checkBoxLowerAdv->isChecked()); m_ui->checkBoxNumbers->setChecked(m_ui->checkBoxNumbersAdv->isChecked()); @@ -342,7 +340,6 @@ void PasswordGeneratorWidget::setAdvancedMode(bool state) | m_ui->checkBoxQuotes->isChecked() | m_ui->checkBoxMath->isChecked() | m_ui->checkBoxDashes->isChecked() | m_ui->checkBoxLogograms->isChecked()); m_ui->checkBoxExtASCII->setChecked(m_ui->checkBoxExtASCIIAdv->isChecked()); - m_ui->simpleBar->show(); } } @@ -523,8 +520,10 @@ void PasswordGeneratorWidget::updateGenerator() m_passwordGenerator->setCharClasses(classes); m_passwordGenerator->setFlags(flags); if (m_ui->buttonAdvancedMode->isChecked()) { + m_passwordGenerator->setAdditionalChars(m_ui->editAdditionalChars->text()); m_passwordGenerator->setExcludedChars(m_ui->editExcludedChars->text()); } else { + m_passwordGenerator->setAdditionalChars(""); m_passwordGenerator->setExcludedChars(""); } diff --git a/src/gui/PasswordGeneratorWidget.ui b/src/gui/PasswordGeneratorWidget.ui index 62d96a2a1..4981d3ccd 100644 --- a/src/gui/PasswordGeneratorWidget.ui +++ b/src/gui/PasswordGeneratorWidget.ui @@ -199,6 +199,89 @@ QProgressBar::chunk { Password + + + + 15 + + + QLayout::SetMinimumSize + + + 0 + + + + + &Length: + + + spinBoxLength + + + + + + + Password length + + + 1 + + + 128 + + + 20 + + + Qt::Horizontal + + + QSlider::TicksBelow + + + 8 + + + + + + + Password length + + + 1 + + + 128 + + + 20 + + + + + + + Qt::TabFocus + + + Switch to advanced mode + + + Advanced + + + true + + + optionButtons + + + + + @@ -401,11 +484,8 @@ QProgressBar::chunk { - - - true - - + + 0 @@ -419,323 +499,454 @@ QProgressBar::chunk { 0 - - - QLayout::SetMinimumSize + + + true - - - - - 40 - 25 - - - - Qt::TabFocus - - - Upper-case letters - - - Upper-case letters - + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QLayout::SetMinimumSize + + + + + + 40 + 25 + + + + Qt::TabFocus + + + Upper-case letters + + + Upper-case letters + + + A-Z + + + true + + + optionButtons + + + + + + + + 40 + 25 + + + + Qt::TabFocus + + + Lower-case letters + + + Lower-case letters + + + a-z + + + true + + + optionButtons + + + + + + + + + QLayout::SetMinimumSize + + + + + + 40 + 25 + + + + Qt::TabFocus + + + Numbers + + + 0-9 + + + true + + + optionButtons + + + + + + + + 40 + 25 + + + + Qt::TabFocus + + + Braces + + + Braces + + + {[( + + + true + + + optionButtons + + + + + + + + + QLayout::SetMinimumSize + + + + + + 40 + 25 + + + + Qt::TabFocus + + + Punctuation + + + Punctuation + + + .,:; + + + true + + + optionButtons + + + + + + + + 40 + 25 + + + + Qt::TabFocus + + + Quotes + + + " ' + + + true + + + optionButtons + + + + + + + + + QLayout::SetMinimumSize + + + + + + 60 + 25 + + + + Qt::TabFocus + + + Math Symbols + + + Math Symbols + + + <*+!?= + + + true + + + optionButtons + + + + + + + + 60 + 25 + + + + Qt::TabFocus + + + Dashes and Slashes + + + Dashes and Slashes + + + \_|-/ + + + true + + + optionButtons + + + + + + + + + QLayout::SetMinimumSize + + + + + + 105 + 25 + + + + Qt::TabFocus + + + Logograms + + + Logograms + + + #$%&&@^`~ + + + true + + + optionButtons + + + + + + + + 105 + 25 + + + + Qt::TabFocus + + + Extended ASCII + + + ExtendedASCII + + + true + + + optionButtons + + + + + + + + + Qt::Horizontal + + + + 0 + 0 + + + + + + + + + + + 0 + + + - A-Z + Also choose from: - - true - - - optionButtons - - - + + + + + 0 + 0 + + - 40 - 25 + 200 + 0 + + Additional characters to use for the generated password + + + Additional characters + + + true + + + + + + + + 0 + 0 + + + + + 200 + 0 + + + + Character set to exclude from generated password + + + Excluded characters + + + true + + + + + + + Do not include: + + + + + Qt::TabFocus - Lower-case letters + Add non-hex letters to "do not include" list - Lower-case letters + Hex Passwords - a-z + Hex - - true - - - optionButtons - - - - QLayout::SetMinimumSize + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - - - - - 40 - 25 - - - - Qt::TabFocus - - - Numbers - - - 0-9 - - - true - - - optionButtons - - - - - - - - 40 - 25 - - - - Qt::TabFocus - - - Braces - - - Braces - - - {[( - - - true - - - optionButtons - - - - + + Exclude look-alike characters + + + optionButtons + + - - - QLayout::SetMinimumSize + + + Pick characters from every group - - - - - 40 - 25 - - - - Qt::TabFocus - - - Punctuation - - - Punctuation - - - .,:; - - - true - - - optionButtons - - - - - - - - 40 - 25 - - - - Qt::TabFocus - - - Quotes - - - " ' - - - true - - - optionButtons - - - - - - - - - QLayout::SetMinimumSize - - - - - - 60 - 25 - - - - Qt::TabFocus - - - Math Symbols - - - Math Symbols - - - <*+!?= - - - true - - - optionButtons - - - - - - - - 60 - 25 - - - - Qt::TabFocus - - - Dashes and Slashes - - - Dashes and Slashes - - - \_|-/ - - - true - - - optionButtons - - - - - - - - - QLayout::SetMinimumSize - - - - - - 105 - 25 - - - - Qt::TabFocus - - - Logograms - - - Logograms - - - #$%&&@^`~ - - - true - - - optionButtons - - - - - - - - 105 - 25 - - - - Qt::TabFocus - - - Extended ASCII - - - ExtendedASCII - - - true - - - optionButtons - - - - - - - - - Qt::Horizontal - - - - 0 - 0 - - - + + optionButtons + + @@ -758,166 +969,12 @@ QProgressBar::chunk { 0 - - - - Do not include: - - - - - - - - 0 - 0 - - - - - 200 - 0 - - - - Character set to exclude from generated password - - - Excluded characters - - - true - - - - - - - Qt::TabFocus - - - Add non-hex letters to "do not include" list - - - Hex Passwords - - - Hex - - - - - - - Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" - - - Exclude look-alike characters - - - optionButtons - - - - - - - Pick characters from every group - - - optionButtons - - - - - - - 15 - - - QLayout::SetMinimumSize - - - 0 - - - - - &Length: - - - spinBoxLength - - - - - - - Password length - - - 1 - - - 128 - - - 20 - - - Qt::Horizontal - - - QSlider::TicksBelow - - - 8 - - - - - - - Password length - - - 1 - - - 128 - - - 20 - - - - - - - Qt::TabFocus - - - Switch to advanced mode - - - Advanced - - - true - - - optionButtons - - - - - @@ -1158,10 +1215,6 @@ QProgressBar::chunk { checkBoxQuotes checkBoxDashes checkBoxExtASCIIAdv - editExcludedChars - buttonAddHex - checkBoxExcludeAlike - checkBoxEnsureEvery comboBoxWordList sliderWordCount spinBoxWordCount diff --git a/tests/TestPasswordGenerator.cpp b/tests/TestPasswordGenerator.cpp index b043a7cd0..89e2eb91c 100644 --- a/tests/TestPasswordGenerator.cpp +++ b/tests/TestPasswordGenerator.cpp @@ -29,6 +29,19 @@ void TestPasswordGenerator::initTestCase() QVERIFY(Crypto::init()); } +void TestPasswordGenerator::testAdditionalChars() +{ + PasswordGenerator generator; + QVERIFY(!generator.isValid()); + generator.setAdditionalChars("aql"); + generator.setLength(2000); + QVERIFY(generator.isValid()); + QString password = generator.generatePassword(); + QCOMPARE(password.size(), 2000); + QRegularExpression regex(R"(^[aql]+$)"); + QVERIFY(regex.match(password).hasMatch()); +} + void TestPasswordGenerator::testCharClasses() { PasswordGenerator generator; diff --git a/tests/TestPasswordGenerator.h b/tests/TestPasswordGenerator.h index 56c4d65a1..454d16e06 100644 --- a/tests/TestPasswordGenerator.h +++ b/tests/TestPasswordGenerator.h @@ -26,6 +26,7 @@ class TestPasswordGenerator : public QObject private slots: void initTestCase(); + void testAdditionalChars(); void testCharClasses(); void testLookalikeExclusion(); };