Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/keepassxreboot/keepassxc.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src/gui
diff options
context:
space:
mode:
authorsnipfoo <79416808+snipfoo@users.noreply.github.com>2021-11-05 06:02:33 +0300
committerGitHub <noreply@github.com>2021-11-05 06:02:33 +0300
commit7811f10dba8a43d2b440ee193d14db55c9d72e31 (patch)
tree7db65c23c164df85fafe21bc1f859f1d7d215345 /src/gui
parentbb88ad6e8ca5344d94c3aef7e6d94c5fc719ab45 (diff)
Support for wordlists in user configuration directory (#6799)
This commit allows users to put alternative wordlists in a `wordlists` subdirectory below their KeePassXC directory (e.g., under Linux, `~/.config/keepassxc/wordlists`). These wordlists will then appear in the dropdown menu in the *Password Generator* widget. In order to differentiate between lists shipped with KeePassXC and user-provided lists, the former appears with a (SYSTEM) prefix.
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/PasswordGeneratorWidget.cpp123
-rw-r--r--src/gui/PasswordGeneratorWidget.h3
-rw-r--r--src/gui/PasswordGeneratorWidget.ui48
3 files changed, 153 insertions, 21 deletions
diff --git a/src/gui/PasswordGeneratorWidget.cpp b/src/gui/PasswordGeneratorWidget.cpp
index 78b240de9..faa6777af 100644
--- a/src/gui/PasswordGeneratorWidget.cpp
+++ b/src/gui/PasswordGeneratorWidget.cpp
@@ -28,7 +28,9 @@
#include "core/PasswordHealth.h"
#include "core/Resources.h"
#include "gui/Clipboard.h"
+#include "gui/FileDialog.h"
#include "gui/Icons.h"
+#include "gui/MessageBox.h"
#include "gui/styles/StateColorPalette.h"
PasswordGeneratorWidget::PasswordGeneratorWidget(QWidget* parent)
@@ -43,6 +45,8 @@ PasswordGeneratorWidget::PasswordGeneratorWidget(QWidget* parent)
m_ui->buttonGenerate->setToolTip(
tr("Regenerate password (%1)").arg(m_ui->buttonGenerate->shortcut().toString(QKeySequence::NativeText)));
m_ui->buttonCopy->setIcon(icons()->icon("clipboard-text"));
+ m_ui->buttonDeleteWordList->setIcon(icons()->icon("trash"));
+ m_ui->buttonAddWordList->setIcon(icons()->icon("document-new"));
m_ui->buttonClose->setShortcut(Qt::Key_Escape);
// Add two shortcuts to save the form CTRL+Enter and CTRL+S
@@ -60,6 +64,8 @@ PasswordGeneratorWidget::PasswordGeneratorWidget(QWidget* parent)
connect(m_ui->buttonApply, SIGNAL(clicked()), SLOT(applyPassword()));
connect(m_ui->buttonCopy, SIGNAL(clicked()), SLOT(copyPassword()));
connect(m_ui->buttonGenerate, SIGNAL(clicked()), SLOT(regeneratePassword()));
+ connect(m_ui->buttonDeleteWordList, SIGNAL(clicked()), SLOT(deleteWordList()));
+ connect(m_ui->buttonAddWordList, SIGNAL(clicked()), SLOT(addWordList()));
connect(m_ui->buttonClose, SIGNAL(clicked()), SIGNAL(closed()));
connect(m_ui->sliderLength, SIGNAL(valueChanged(int)), SLOT(passwordLengthChanged(int)));
@@ -92,15 +98,18 @@ PasswordGeneratorWidget::PasswordGeneratorWidget(QWidget* parent)
m_ui->wordCaseComboBox->addItem(tr("UPPER CASE"), PassphraseGenerator::UPPERCASE);
m_ui->wordCaseComboBox->addItem(tr("Title Case"), PassphraseGenerator::TITLECASE);
+ // load system-wide wordlists
QDir path(resources()->wordlistPath(""));
- 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);
+ for (const auto& fileName : path.entryList(QDir::Files)) {
+ m_ui->comboBoxWordList->addItem(tr("(SYSTEM)") + " " + fileName, fileName);
+ }
+
+ m_firstCustomWordlistIndex = m_ui->comboBoxWordList->count();
+
+ // load user-provided wordlists
+ path = QDir(resources()->userWordlistPath(""));
+ for (const auto& fileName : path.entryList(QDir::Files)) {
+ m_ui->comboBoxWordList->addItem(fileName, path.absolutePath() + QDir::separator() + fileName);
}
loadSettings();
@@ -164,7 +173,10 @@ void PasswordGeneratorWidget::loadSettings()
// Diceware config
m_ui->spinBoxWordCount->setValue(config()->get(Config::PasswordGenerator_WordCount).toInt());
m_ui->editWordSeparator->setText(config()->get(Config::PasswordGenerator_WordSeparator).toString());
- m_ui->comboBoxWordList->setCurrentText(config()->get(Config::PasswordGenerator_WordList).toString());
+ int i = m_ui->comboBoxWordList->findData(config()->get(Config::PasswordGenerator_WordList).toString());
+ if (i > -1) {
+ m_ui->comboBoxWordList->setCurrentIndex(i);
+ }
m_ui->wordCaseComboBox->setCurrentIndex(config()->get(Config::PasswordGenerator_WordCase).toInt());
// Password or diceware?
@@ -205,7 +217,7 @@ void PasswordGeneratorWidget::saveSettings()
// Diceware config
config()->set(Config::PasswordGenerator_WordCount, m_ui->spinBoxWordCount->value());
config()->set(Config::PasswordGenerator_WordSeparator, m_ui->editWordSeparator->text());
- config()->set(Config::PasswordGenerator_WordList, m_ui->comboBoxWordList->currentText());
+ config()->set(Config::PasswordGenerator_WordList, m_ui->comboBoxWordList->currentData());
config()->set(Config::PasswordGenerator_WordCase, m_ui->wordCaseComboBox->currentIndex());
// Password or diceware?
@@ -329,6 +341,86 @@ bool PasswordGeneratorWidget::isPasswordVisible() const
return m_ui->editNewPassword->isPasswordVisible();
}
+void PasswordGeneratorWidget::deleteWordList()
+{
+ if (m_ui->comboBoxWordList->currentIndex() < m_firstCustomWordlistIndex) {
+ return;
+ }
+
+ QFile file(m_ui->comboBoxWordList->currentData().toString());
+ if (!file.exists()) {
+ return;
+ }
+
+ auto result = MessageBox::question(this,
+ tr("Confirm Delete Wordlist"),
+ tr("Do you really want to delete the wordlist \"%1\"?").arg(file.fileName()),
+ MessageBox::Delete | MessageBox::Cancel,
+ MessageBox::Cancel);
+ if (result != MessageBox::Delete) {
+ return;
+ }
+
+ if (!file.remove()) {
+ MessageBox::critical(this, tr("Failed to delete wordlist"), file.errorString());
+ return;
+ }
+
+ m_ui->comboBoxWordList->removeItem(m_ui->comboBoxWordList->currentIndex());
+ updateGenerator();
+}
+
+void PasswordGeneratorWidget::addWordList()
+{
+ auto filter = QString("%1 (*.txt *.asc *.wordlist);;%2 (*)").arg(tr("Wordlists"), tr("All files"));
+ auto filePath = fileDialog()->getOpenFileName(this, tr("Select Custom Wordlist"), "", filter);
+ if (filePath.isEmpty()) {
+ return;
+ }
+
+ // create directory for user-specified wordlists, if necessary
+ QDir destDir(resources()->userWordlistPath(""));
+ destDir.mkpath(".");
+
+ // check if destination wordlist already exists
+ QString fileName = QFileInfo(filePath).fileName();
+ QString destPath = destDir.absolutePath() + QDir::separator() + fileName;
+ QFile dest(destPath);
+ if (dest.exists()) {
+ auto response = MessageBox::warning(this,
+ tr("Overwrite Wordlist?"),
+ tr("Wordlist \"%1\" already exists as a custom wordlist.\n"
+ "Do you want to overwrite it?")
+ .arg(fileName),
+ MessageBox::Overwrite | MessageBox::Cancel,
+ MessageBox::Cancel);
+ if (response != MessageBox::Overwrite) {
+ return;
+ }
+ if (!dest.remove()) {
+ MessageBox::critical(this, tr("Failed to delete wordlist"), dest.errorString());
+ return;
+ }
+ }
+
+ // copy wordlist to destination path and add corresponding item to the combo box
+ QFile file(filePath);
+ if (!file.copy(destPath)) {
+ MessageBox::critical(this, tr("Failed to add wordlist"), file.errorString());
+ return;
+ }
+
+ auto index = m_ui->comboBoxWordList->findData(destPath);
+ if (index == -1) {
+ m_ui->comboBoxWordList->addItem(fileName, destPath);
+ index = m_ui->comboBoxWordList->count() - 1;
+ }
+ m_ui->comboBoxWordList->setCurrentIndex(index);
+
+ // update the password generator
+ updateGenerator();
+}
+
void PasswordGeneratorWidget::setAdvancedMode(bool advanced)
{
saveSettings();
@@ -540,10 +632,15 @@ void PasswordGeneratorWidget::updateGenerator()
static_cast<PassphraseGenerator::PassphraseWordCase>(m_ui->wordCaseComboBox->currentData().toInt()));
m_dicewareGenerator->setWordCount(m_ui->spinBoxWordCount->value());
- if (!m_ui->comboBoxWordList->currentText().isEmpty()) {
- QString path = resources()->wordlistPath(m_ui->comboBoxWordList->currentText());
- m_dicewareGenerator->setWordList(path);
+ auto path = m_ui->comboBoxWordList->currentData().toString();
+ if (m_ui->comboBoxWordList->currentIndex() < m_firstCustomWordlistIndex) {
+ path = resources()->wordlistPath(path);
+ m_ui->buttonDeleteWordList->setEnabled(false);
+ } else {
+ m_ui->buttonDeleteWordList->setEnabled(true);
}
+ m_dicewareGenerator->setWordList(path);
+
m_dicewareGenerator->setWordSeparator(m_ui->editWordSeparator->text());
if (m_dicewareGenerator->isValid()) {
diff --git a/src/gui/PasswordGeneratorWidget.h b/src/gui/PasswordGeneratorWidget.h
index 50de172ac..57b331bb8 100644
--- a/src/gui/PasswordGeneratorWidget.h
+++ b/src/gui/PasswordGeneratorWidget.h
@@ -61,6 +61,8 @@ public slots:
void applyPassword();
void copyPassword();
void setPasswordVisible(bool visible);
+ void deleteWordList();
+ void addWordList();
signals:
void appliedPassword(const QString& password);
@@ -80,6 +82,7 @@ private slots:
private:
bool m_standalone = false;
+ int m_firstCustomWordlistIndex;
void closeEvent(QCloseEvent* event);
PasswordGenerator::CharClasses charClasses();
diff --git a/src/gui/PasswordGeneratorWidget.ui b/src/gui/PasswordGeneratorWidget.ui
index 01ccedc01..547c5a0ab 100644
--- a/src/gui/PasswordGeneratorWidget.ui
+++ b/src/gui/PasswordGeneratorWidget.ui
@@ -862,14 +862,44 @@ QProgressBar::chunk {
</layout>
</item>
<item row="0" column="2">
- <widget class="QComboBox" name="comboBoxWordList">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- </widget>
+ <layout class="QHBoxLayout" name="horizontalLayout_10">
+ <item>
+ <widget class="QComboBox" name="comboBoxWordList">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonDeleteWordList">
+ <property name="focusPolicy">
+ <enum>Qt::TabFocus</enum>
+ </property>
+ <property name="toolTip">
+ <string>Delete selected wordlist</string>
+ </property>
+ <property name="accessibleDescription">
+ <string>Delete selected wordlist</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonAddWordList">
+ <property name="focusPolicy">
+ <enum>Qt::TabFocus</enum>
+ </property>
+ <property name="toolTip">
+ <string>Add custom wordlist</string>
+ </property>
+ <property name="accessibleDescription">
+ <string>Add custom wordlist</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
</item>
<item row="4" column="2" alignment="Qt::AlignLeft">
<widget class="QLabel" name="charactersInPassphraseLabel">
@@ -990,6 +1020,8 @@ QProgressBar::chunk {
<tabstop>checkBoxExcludeAlike</tabstop>
<tabstop>checkBoxEnsureEvery</tabstop>
<tabstop>comboBoxWordList</tabstop>
+ <tabstop>buttonDeleteWordList</tabstop>
+ <tabstop>buttonAddWordList</tabstop>
<tabstop>sliderWordCount</tabstop>
<tabstop>spinBoxWordCount</tabstop>
<tabstop>editWordSeparator</tabstop>