Various minor bug fixes / enhancements

* Fix issues when Config options were renamed
* Fix compile issues when using clang 10
* Rearrange database menu icons and import database menu icons
* Set minimum size of MainWindow to 800 to prevent search bar from hiding
* Fix not saving password generator options when closing the standalone generator
* Add headers to health check reports
* Don't show hidden content dots when notes are hidden but empty.

* Fix saving new database files in SMB shares on Windows, fixes #4809

* Gracefully handle duplicate attachments :
Instead of bailing out with an error, prepend a random string to the name of duplicate attachment records. This prevents data loss from other programs that mishandled KDBX XML writing. Fixes #2493

* Properly handle blocked import of signed KeeShare database, fixes #4413
This commit is contained in:
Jonathan White 2020-06-04 08:11:12 -04:00
parent e36cba703e
commit c830f85c09
19 changed files with 101 additions and 80 deletions

View file

@ -75,7 +75,7 @@ static const QHash<Config::ConfigKey, ConfigDirective> configStrings = {
{Config::GlobalAutoTypeModifiers,{QS("GlobalAutoTypeModifiers"), Roaming, 0}}, {Config::GlobalAutoTypeModifiers,{QS("GlobalAutoTypeModifiers"), Roaming, 0}},
{Config::TrackNonDataChanges,{QS("TrackNonDataChanges"), Roaming, false}}, {Config::TrackNonDataChanges,{QS("TrackNonDataChanges"), Roaming, false}},
{Config::FaviconDownloadTimeout,{QS("FaviconDownloadTimeout"), Roaming, 10}}, {Config::FaviconDownloadTimeout,{QS("FaviconDownloadTimeout"), Roaming, 10}},
{Config::UpdateCheckMessageShown,{QS("UpdateCheckMessageShown"), Roaming, true}}, {Config::UpdateCheckMessageShown,{QS("UpdateCheckMessageShown"), Roaming, false}},
{Config::UseTouchID,{QS("UseTouchID"), Roaming, false}}, {Config::UseTouchID,{QS("UseTouchID"), Roaming, false}},
{Config::LastDatabases, {QS("LastDatabases"), Local, {}}}, {Config::LastDatabases, {QS("LastDatabases"), Local, {}}},
@ -102,6 +102,7 @@ static const QHash<Config::ConfigKey, ConfigDirective> configStrings = {
{Config::GUI_MonospaceNotes, {QS("GUI/MonospaceNotes"), Roaming, false}}, {Config::GUI_MonospaceNotes, {QS("GUI/MonospaceNotes"), Roaming, false}},
{Config::GUI_ApplicationTheme, {QS("GUI/ApplicationTheme"), Roaming, QS("auto")}}, {Config::GUI_ApplicationTheme, {QS("GUI/ApplicationTheme"), Roaming, QS("auto")}},
{Config::GUI_CheckForUpdates, {QS("GUI/CheckForUpdates"), Roaming, true}}, {Config::GUI_CheckForUpdates, {QS("GUI/CheckForUpdates"), Roaming, true}},
{Config::GUI_CheckForUpdatesNextCheck, {QS("GUI/CheckForUpdatesNextCheck"), Local, 0}},
{Config::GUI_CheckForUpdatesIncludeBetas, {QS("GUI/CheckForUpdatesIncludeBetas"), Roaming, false}}, {Config::GUI_CheckForUpdatesIncludeBetas, {QS("GUI/CheckForUpdatesIncludeBetas"), Roaming, false}},
{Config::GUI_MainWindowGeometry, {QS("GUI/MainWindowGeometry"), Local, {}}}, {Config::GUI_MainWindowGeometry, {QS("GUI/MainWindowGeometry"), Local, {}}},
@ -111,7 +112,6 @@ static const QHash<Config::ConfigKey, ConfigDirective> configStrings = {
{Config::GUI_SplitterState, {QS("GUI/SplitterState"), Local, {}}}, {Config::GUI_SplitterState, {QS("GUI/SplitterState"), Local, {}}},
{Config::GUI_PreviewSplitterState, {QS("GUI/PreviewSplitterState"), Local, {}}}, {Config::GUI_PreviewSplitterState, {QS("GUI/PreviewSplitterState"), Local, {}}},
{Config::GUI_AutoTypeSelectDialogSize, {QS("GUI/AutoTypeSelectDialogSize"), Local, QSize(600, 250)}}, {Config::GUI_AutoTypeSelectDialogSize, {QS("GUI/AutoTypeSelectDialogSize"), Local, QSize(600, 250)}},
{Config::GUI_CheckForUpdatesNextCheck, {QS("GUI/AutoTypeSelectDialogSize"), Local, 0}},
// Security // Security
{Config::Security_ClearClipboard, {QS("Security/ClearClipboard"), Roaming, true}}, {Config::Security_ClearClipboard, {QS("Security/ClearClipboard"), Roaming, true}},
@ -185,13 +185,13 @@ static const QHash<Config::ConfigKey, ConfigDirective> configStrings = {
{Config::PasswordGenerator_EASCII, {QS("PasswordGenerator/EASCII"), Roaming, false}}, {Config::PasswordGenerator_EASCII, {QS("PasswordGenerator/EASCII"), Roaming, false}},
{Config::PasswordGenerator_AdvancedMode, {QS("PasswordGenerator/AdvancedMode"), Roaming, false}}, {Config::PasswordGenerator_AdvancedMode, {QS("PasswordGenerator/AdvancedMode"), Roaming, false}},
{Config::PasswordGenerator_SpecialChars, {QS("PasswordGenerator/SpecialChars"), Roaming, true}}, {Config::PasswordGenerator_SpecialChars, {QS("PasswordGenerator/SpecialChars"), Roaming, true}},
{Config::PasswordGenerator_AdditionalChars, {QS("PasswordGenerator/AdditionalChars"), Roaming, true}},
{Config::PasswordGenerator_Braces, {QS("PasswordGenerator/Braces"), Roaming, false}}, {Config::PasswordGenerator_Braces, {QS("PasswordGenerator/Braces"), Roaming, false}},
{Config::PasswordGenerator_Punctuation, {QS("PasswordGenerator/Punctuation"), Roaming, false}}, {Config::PasswordGenerator_Punctuation, {QS("PasswordGenerator/Punctuation"), Roaming, false}},
{Config::PasswordGenerator_Quotes, {QS("PasswordGenerator/Quotes"), Roaming, false}}, {Config::PasswordGenerator_Quotes, {QS("PasswordGenerator/Quotes"), Roaming, false}},
{Config::PasswordGenerator_Dashes, {QS("PasswordGenerator/Dashes"), Roaming, false}}, {Config::PasswordGenerator_Dashes, {QS("PasswordGenerator/Dashes"), Roaming, false}},
{Config::PasswordGenerator_Math, {QS("PasswordGenerator/Math"), Roaming, false}}, {Config::PasswordGenerator_Math, {QS("PasswordGenerator/Math"), Roaming, false}},
{Config::PasswordGenerator_Logograms, {QS("PasswordGenerator/Logograms"), Roaming, false}}, {Config::PasswordGenerator_Logograms, {QS("PasswordGenerator/Logograms"), Roaming, false}},
{Config::PasswordGenerator_AdditionalChars, {QS("PasswordGenerator/AdditionalChars"), Roaming, {}}},
{Config::PasswordGenerator_ExcludedChars, {QS("PasswordGenerator/ExcludedChars"), Roaming, {}}}, {Config::PasswordGenerator_ExcludedChars, {QS("PasswordGenerator/ExcludedChars"), Roaming, {}}},
{Config::PasswordGenerator_ExcludeAlike, {QS("PasswordGenerator/ExcludeAlike"), Roaming, true}}, {Config::PasswordGenerator_ExcludeAlike, {QS("PasswordGenerator/ExcludeAlike"), Roaming, true}},
{Config::PasswordGenerator_EnsureEvery, {QS("PasswordGenerator/EnsureEvery"), Roaming, true}}, {Config::PasswordGenerator_EnsureEvery, {QS("PasswordGenerator/EnsureEvery"), Roaming, true}},

View file

@ -251,12 +251,13 @@ bool Database::saveAs(const QString& filePath, QString* error, bool atomic, bool
setReadOnly(false); setReadOnly(false);
m_fileWatcher->stop(); m_fileWatcher->stop();
auto& canonicalFilePath = QFileInfo::exists(filePath) ? QFileInfo(filePath).canonicalFilePath() : filePath; QFileInfo fileInfo(filePath);
bool ok = AsyncTask::runAndWaitForFuture([&] { return performSave(canonicalFilePath, error, atomic, backup); }); auto realFilePath = fileInfo.exists() ? fileInfo.canonicalFilePath() : fileInfo.absoluteFilePath();
bool ok = AsyncTask::runAndWaitForFuture([&] { return performSave(realFilePath, error, atomic, backup); });
if (ok) { if (ok) {
markAsClean(); markAsClean();
setFilePath(filePath); setFilePath(filePath);
m_fileWatcher->start(canonicalFilePath, 30, 1); m_fileWatcher->start(realFilePath, 30, 1);
} else { } else {
// Saving failed, don't rewatch file since it does not represent our database // Saving failed, don't rewatch file since it does not represent our database
markAsModified(); markAsModified();

View file

@ -142,7 +142,7 @@ QSharedPointer<PasswordHealth> HealthChecker::evaluate(const Entry* entry) const
for (int i = 0; i < used.size(); ++i) { for (int i = 0; i < used.size(); ++i) {
health->addScoreDetails(used[i]); health->addScoreDetails(used[i]);
if (i == 19) { if (i == 19) {
health->addScoreDetails(QStringLiteral("...")); health->addScoreDetails("");
break; break;
} }
} }

View file

@ -82,7 +82,7 @@ bcrypt_hash(const quint8* sha2pass, const quint8* sha2salt, quint8* out)
cdata[i] = Blowfish_stream2word(ciphertext, sizeof(ciphertext), cdata[i] = Blowfish_stream2word(ciphertext, sizeof(ciphertext),
&j); &j);
for (i = 0; i < 64; i++) for (i = 0; i < 64; i++)
blf_enc(&state, cdata, sizeof(cdata) / sizeof(uint64_t)); blf_enc(&state, cdata, BCRYPT_WORDS / 2);
/* copy out */ /* copy out */
for (i = 0; i < BCRYPT_WORDS; i++) { for (i = 0; i < BCRYPT_WORDS; i++) {

View file

@ -875,11 +875,13 @@ QPair<QString, QString> KdbxXmlReader::parseEntryBinary(Entry* entry)
} }
if (keySet && valueSet) { if (keySet && valueSet) {
if (entry->attachments()->hasKey(key)) { if (entry->attachments()->hasKey(key) && entry->attachments()->value(key) != value) {
raiseError(tr("Duplicate attachment found")); // NOTE: This only impacts KDBX 3.x databases
} else { // Prepend a random string to the key to make it unique and prevent data loss
entry->attachments()->set(key, value); key = key.prepend(QUuid::createUuid().toString().mid(1, 8) + "_");
qWarning("Duplicate attachment name found, renamed to: %s", qPrintable(key));
} }
entry->attachments()->set(key, value);
} else { } else {
raiseError(tr("Entry binary key or value missing")); raiseError(tr("Entry binary key or value missing"));
} }

View file

@ -333,7 +333,7 @@ MainWindow::MainWindow()
m_ui->actionDatabaseSaveBackup->setIcon(resources()->icon("document-save-copy")); m_ui->actionDatabaseSaveBackup->setIcon(resources()->icon("document-save-copy"));
m_ui->actionDatabaseClose->setIcon(resources()->icon("document-close")); m_ui->actionDatabaseClose->setIcon(resources()->icon("document-close"));
m_ui->actionReports->setIcon(resources()->icon("reports")); m_ui->actionReports->setIcon(resources()->icon("reports"));
m_ui->actionChangeDatabaseSettings->setIcon(resources()->icon("document-edit")); m_ui->actionDatabaseSettings->setIcon(resources()->icon("document-edit"));
m_ui->actionChangeMasterKey->setIcon(resources()->icon("database-change-key")); m_ui->actionChangeMasterKey->setIcon(resources()->icon("database-change-key"));
m_ui->actionLockDatabases->setIcon(resources()->icon("database-lock")); m_ui->actionLockDatabases->setIcon(resources()->icon("database-lock"));
m_ui->actionQuit->setIcon(resources()->icon("application-exit")); m_ui->actionQuit->setIcon(resources()->icon("application-exit"));
@ -413,7 +413,7 @@ MainWindow::MainWindow()
connect(m_ui->actionDatabaseMerge, SIGNAL(triggered()), m_ui->tabWidget, SLOT(mergeDatabase())); connect(m_ui->actionDatabaseMerge, SIGNAL(triggered()), m_ui->tabWidget, SLOT(mergeDatabase()));
connect(m_ui->actionChangeMasterKey, SIGNAL(triggered()), m_ui->tabWidget, SLOT(changeMasterKey())); connect(m_ui->actionChangeMasterKey, SIGNAL(triggered()), m_ui->tabWidget, SLOT(changeMasterKey()));
connect(m_ui->actionReports, SIGNAL(triggered()), m_ui->tabWidget, SLOT(changeReports())); connect(m_ui->actionReports, SIGNAL(triggered()), m_ui->tabWidget, SLOT(changeReports()));
connect(m_ui->actionChangeDatabaseSettings, SIGNAL(triggered()), m_ui->tabWidget, SLOT(changeDatabaseSettings())); connect(m_ui->actionDatabaseSettings, SIGNAL(triggered()), m_ui->tabWidget, SLOT(changeDatabaseSettings()));
connect(m_ui->actionImportCsv, SIGNAL(triggered()), m_ui->tabWidget, SLOT(importCsv())); connect(m_ui->actionImportCsv, SIGNAL(triggered()), m_ui->tabWidget, SLOT(importCsv()));
connect(m_ui->actionImportKeePass1, SIGNAL(triggered()), m_ui->tabWidget, SLOT(importKeePass1Database())); connect(m_ui->actionImportKeePass1, SIGNAL(triggered()), m_ui->tabWidget, SLOT(importKeePass1Database()));
connect(m_ui->actionImportOpVault, SIGNAL(triggered()), m_ui->tabWidget, SLOT(importOpVaultDatabase())); connect(m_ui->actionImportOpVault, SIGNAL(triggered()), m_ui->tabWidget, SLOT(importOpVaultDatabase()));
@ -456,8 +456,11 @@ MainWindow::MainWindow()
m_actionMultiplexer.connect(m_ui->actionGroupDownloadFavicons, SIGNAL(triggered()), SLOT(downloadAllFavicons())); m_actionMultiplexer.connect(m_ui->actionGroupDownloadFavicons, SIGNAL(triggered()), SLOT(downloadAllFavicons()));
connect(m_ui->actionSettings, SIGNAL(toggled(bool)), SLOT(switchToSettings(bool))); connect(m_ui->actionSettings, SIGNAL(toggled(bool)), SLOT(switchToSettings(bool)));
connect(m_ui->actionPasswordGenerator, SIGNAL(toggled(bool)), SLOT(switchToPasswordGen(bool))); connect(m_ui->actionPasswordGenerator, SIGNAL(toggled(bool)), SLOT(togglePasswordGenerator(bool)));
connect(m_ui->passwordGeneratorWidget, SIGNAL(closePasswordGenerator()), SLOT(closePasswordGen())); connect(m_ui->passwordGeneratorWidget, &PasswordGeneratorWidget::closed, this, [this] {
togglePasswordGenerator(false);
});
m_ui->passwordGeneratorWidget->setStandaloneMode(true);
connect(m_ui->welcomeWidget, SIGNAL(newDatabase()), SLOT(switchToNewDatabase())); connect(m_ui->welcomeWidget, SIGNAL(newDatabase()), SLOT(switchToNewDatabase()));
connect(m_ui->welcomeWidget, SIGNAL(openDatabase()), SLOT(switchToOpenDatabase())); connect(m_ui->welcomeWidget, SIGNAL(openDatabase()), SLOT(switchToOpenDatabase()));
@ -719,7 +722,7 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
&& !recycleBinSelected); && !recycleBinSelected);
m_ui->actionChangeMasterKey->setEnabled(true); m_ui->actionChangeMasterKey->setEnabled(true);
m_ui->actionReports->setEnabled(true); m_ui->actionReports->setEnabled(true);
m_ui->actionChangeDatabaseSettings->setEnabled(true); m_ui->actionDatabaseSettings->setEnabled(true);
m_ui->actionDatabaseSave->setEnabled(m_ui->tabWidget->canSave()); m_ui->actionDatabaseSave->setEnabled(m_ui->tabWidget->canSave());
m_ui->actionDatabaseSaveAs->setEnabled(true); m_ui->actionDatabaseSaveAs->setEnabled(true);
m_ui->actionDatabaseSaveBackup->setEnabled(true); m_ui->actionDatabaseSaveBackup->setEnabled(true);
@ -775,7 +778,7 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
m_ui->actionChangeMasterKey->setEnabled(false); m_ui->actionChangeMasterKey->setEnabled(false);
m_ui->actionReports->setEnabled(false); m_ui->actionReports->setEnabled(false);
m_ui->actionChangeDatabaseSettings->setEnabled(false); m_ui->actionDatabaseSettings->setEnabled(false);
m_ui->actionDatabaseSave->setEnabled(false); m_ui->actionDatabaseSave->setEnabled(false);
m_ui->actionDatabaseSaveAs->setEnabled(false); m_ui->actionDatabaseSaveAs->setEnabled(false);
m_ui->actionDatabaseSaveBackup->setEnabled(false); m_ui->actionDatabaseSaveBackup->setEnabled(false);
@ -804,7 +807,7 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
m_ui->actionChangeMasterKey->setEnabled(false); m_ui->actionChangeMasterKey->setEnabled(false);
m_ui->actionReports->setEnabled(false); m_ui->actionReports->setEnabled(false);
m_ui->actionChangeDatabaseSettings->setEnabled(false); m_ui->actionDatabaseSettings->setEnabled(false);
m_ui->actionDatabaseSave->setEnabled(false); m_ui->actionDatabaseSave->setEnabled(false);
m_ui->actionDatabaseSaveAs->setEnabled(false); m_ui->actionDatabaseSaveAs->setEnabled(false);
m_ui->actionDatabaseSaveBackup->setEnabled(false); m_ui->actionDatabaseSaveBackup->setEnabled(false);
@ -990,24 +993,18 @@ void MainWindow::switchToSettings(bool enabled)
} }
} }
void MainWindow::switchToPasswordGen(bool enabled) void MainWindow::togglePasswordGenerator(bool enabled)
{ {
if (enabled) { if (enabled) {
m_ui->passwordGeneratorWidget->loadSettings(); m_ui->passwordGeneratorWidget->loadSettings();
m_ui->passwordGeneratorWidget->regeneratePassword(); m_ui->passwordGeneratorWidget->regeneratePassword();
m_ui->stackedWidget->setCurrentIndex(PasswordGeneratorScreen); m_ui->stackedWidget->setCurrentIndex(PasswordGeneratorScreen);
m_ui->passwordGeneratorWidget->setStandaloneMode(true);
} else { } else {
m_ui->passwordGeneratorWidget->saveSettings(); m_ui->passwordGeneratorWidget->saveSettings();
switchToDatabases(); switchToDatabases();
} }
} }
void MainWindow::closePasswordGen()
{
switchToPasswordGen(false);
}
void MainWindow::switchToNewDatabase() void MainWindow::switchToNewDatabase()
{ {
m_ui->tabWidget->newDatabase(); m_ui->tabWidget->newDatabase();

View file

@ -104,14 +104,13 @@ private slots:
void openKeyboardShortcuts(); void openKeyboardShortcuts();
void switchToDatabases(); void switchToDatabases();
void switchToSettings(bool enabled); void switchToSettings(bool enabled);
void switchToPasswordGen(bool enabled); void togglePasswordGenerator(bool enabled);
void switchToNewDatabase(); void switchToNewDatabase();
void switchToOpenDatabase(); void switchToOpenDatabase();
void switchToDatabaseFile(const QString& file); void switchToDatabaseFile(const QString& file);
void switchToKeePass1Database(); void switchToKeePass1Database();
void switchToOpVaultDatabase(); void switchToOpVaultDatabase();
void switchToCsvImport(); void switchToCsvImport();
void closePasswordGen();
void databaseStatusChanged(DatabaseWidget* dbWidget); void databaseStatusChanged(DatabaseWidget* dbWidget);
void databaseTabChanged(int tabIndex); void databaseTabChanged(int tabIndex);
void openRecentDatabase(QAction* action); void openRecentDatabase(QAction* action);

View file

@ -13,6 +13,12 @@
<height>600</height> <height>600</height>
</rect> </rect>
</property> </property>
<property name="minimumSize">
<size>
<width>800</width>
<height>0</height>
</size>
</property>
<property name="windowTitle"> <property name="windowTitle">
<string notr="true">KeePassXC</string> <string notr="true">KeePassXC</string>
</property> </property>
@ -229,9 +235,9 @@
<property name="title"> <property name="title">
<string>&amp;Import</string> <string>&amp;Import</string>
</property> </property>
<addaction name="actionImportKeePass1"/>
<addaction name="actionImportOpVault"/>
<addaction name="actionImportCsv"/> <addaction name="actionImportCsv"/>
<addaction name="actionImportOpVault"/>
<addaction name="actionImportKeePass1"/>
</widget> </widget>
<widget class="QMenu" name="menuExport"> <widget class="QMenu" name="menuExport">
<property name="title"> <property name="title">
@ -248,9 +254,9 @@
<addaction name="actionDatabaseSaveBackup"/> <addaction name="actionDatabaseSaveBackup"/>
<addaction name="actionDatabaseClose"/> <addaction name="actionDatabaseClose"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionChangeMasterKey"/>
<addaction name="actionReports"/> <addaction name="actionReports"/>
<addaction name="actionChangeDatabaseSettings"/> <addaction name="actionDatabaseSettings"/>
<addaction name="actionChangeMasterKey"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionDatabaseMerge"/> <addaction name="actionDatabaseMerge"/>
<addaction name="menuImport"/> <addaction name="menuImport"/>
@ -381,9 +387,9 @@
<addaction name="actionEntryCopyURL"/> <addaction name="actionEntryCopyURL"/>
<addaction name="actionEntryAutoType"/> <addaction name="actionEntryAutoType"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionPasswordGenerator"/>
<addaction name="actionLockDatabases"/> <addaction name="actionLockDatabases"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionPasswordGenerator"/>
<addaction name="actionSettings"/> <addaction name="actionSettings"/>
<addaction name="separator"/> <addaction name="separator"/>
</widget> </widget>
@ -550,7 +556,7 @@
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="text"> <property name="text">
<string>&amp;Reports...</string> <string>&amp;Database Reports...</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Statistics, health check, etc.</string> <string>Statistics, health check, etc.</string>
@ -559,7 +565,7 @@
<enum>QAction::NoRole</enum> <enum>QAction::NoRole</enum>
</property> </property>
</action> </action>
<action name="actionChangeDatabaseSettings"> <action name="actionDatabaseSettings">
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>false</bool>
</property> </property>
@ -711,7 +717,7 @@
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="text"> <property name="text">
<string>&amp;Export to CSV File…</string> <string>&amp;CSV File…</string>
</property> </property>
</action> </action>
<action name="actionExportHtml"> <action name="actionExportHtml">
@ -719,7 +725,7 @@
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="text"> <property name="text">
<string>&amp;Export to HTML File…</string> <string>&amp;HTML File…</string>
</property> </property>
</action> </action>
<action name="actionImportKeePass1"> <action name="actionImportKeePass1">

View file

@ -44,6 +44,14 @@ PasswordGeneratorWidget::PasswordGeneratorWidget(QWidget* parent)
m_ui->buttonCopy->setIcon(resources()->icon("clipboard-text")); m_ui->buttonCopy->setIcon(resources()->icon("clipboard-text"));
m_ui->buttonClose->setShortcut(Qt::Key_Escape); m_ui->buttonClose->setShortcut(Qt::Key_Escape);
m_ui->clearInclude->setIcon(resources()->icon("edit-clear-locationbar-rtl"));
m_ui->editAdditionalChars->addAction(m_ui->clearInclude, QLineEdit::TrailingPosition);
m_ui->clearInclude->setVisible(false);
m_ui->clearExclude->setIcon(resources()->icon("edit-clear-locationbar-rtl"));
m_ui->editExcludedChars->addAction(m_ui->clearExclude, QLineEdit::TrailingPosition);
m_ui->clearExclude->setVisible(false);
connect(m_ui->editNewPassword, SIGNAL(textChanged(QString)), SLOT(updateButtonsEnabled(QString))); connect(m_ui->editNewPassword, SIGNAL(textChanged(QString)), SLOT(updateButtonsEnabled(QString)));
connect(m_ui->editNewPassword, SIGNAL(textChanged(QString)), SLOT(updatePasswordStrength(QString))); connect(m_ui->editNewPassword, SIGNAL(textChanged(QString)), SLOT(updatePasswordStrength(QString)));
connect(m_ui->buttonAdvancedMode, SIGNAL(toggled(bool)), SLOT(setAdvancedMode(bool))); connect(m_ui->buttonAdvancedMode, SIGNAL(toggled(bool)), SLOT(setAdvancedMode(bool)));
@ -53,7 +61,9 @@ PasswordGeneratorWidget::PasswordGeneratorWidget(QWidget* parent)
connect(m_ui->buttonApply, SIGNAL(clicked()), SLOT(applyPassword())); connect(m_ui->buttonApply, SIGNAL(clicked()), SLOT(applyPassword()));
connect(m_ui->buttonCopy, SIGNAL(clicked()), SLOT(copyPassword())); connect(m_ui->buttonCopy, SIGNAL(clicked()), SLOT(copyPassword()));
connect(m_ui->buttonGenerate, SIGNAL(clicked()), SLOT(regeneratePassword())); connect(m_ui->buttonGenerate, SIGNAL(clicked()), SLOT(regeneratePassword()));
connect(m_ui->buttonClose, SIGNAL(clicked()), SIGNAL(closePasswordGenerator())); connect(m_ui->buttonClose, SIGNAL(clicked()), SIGNAL(closed()));
connect(m_ui->clearInclude, SIGNAL(triggered(bool)), m_ui->editAdditionalChars, SLOT(clear()));
connect(m_ui->clearExclude, SIGNAL(triggered(bool)), m_ui->editExcludedChars, SLOT(clear()));
connect(m_ui->sliderLength, SIGNAL(valueChanged(int)), SLOT(passwordLengthChanged(int))); connect(m_ui->sliderLength, SIGNAL(valueChanged(int)), SLOT(passwordLengthChanged(int)));
connect(m_ui->spinBoxLength, SIGNAL(valueChanged(int)), SLOT(passwordLengthChanged(int))); connect(m_ui->spinBoxLength, SIGNAL(valueChanged(int)), SLOT(passwordLengthChanged(int)));
@ -110,7 +120,7 @@ PasswordGeneratorWidget* PasswordGeneratorWidget::popupGenerator(QWidget* parent
pwGenerator->setWindowFlags(Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint); pwGenerator->setWindowFlags(Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint);
pwGenerator->setStandaloneMode(false); pwGenerator->setStandaloneMode(false);
connect(pwGenerator, SIGNAL(closePasswordGenerator()), pwGenerator, SLOT(deleteLater())); connect(pwGenerator, SIGNAL(closed()), pwGenerator, SLOT(deleteLater()));
pwGenerator->show(); pwGenerator->show();
pwGenerator->raise(); pwGenerator->raise();
@ -180,6 +190,7 @@ void PasswordGeneratorWidget::saveSettings()
config()->set(Config::PasswordGenerator_Dashes, m_ui->checkBoxDashes->isChecked()); config()->set(Config::PasswordGenerator_Dashes, m_ui->checkBoxDashes->isChecked());
config()->set(Config::PasswordGenerator_Math, m_ui->checkBoxMath->isChecked()); config()->set(Config::PasswordGenerator_Math, m_ui->checkBoxMath->isChecked());
config()->set(Config::PasswordGenerator_Logograms, m_ui->checkBoxLogograms->isChecked()); config()->set(Config::PasswordGenerator_Logograms, m_ui->checkBoxLogograms->isChecked());
config()->set(Config::PasswordGenerator_AdditionalChars, m_ui->editAdditionalChars->text());
config()->set(Config::PasswordGenerator_ExcludedChars, m_ui->editExcludedChars->text()); config()->set(Config::PasswordGenerator_ExcludedChars, m_ui->editExcludedChars->text());
config()->set(Config::PasswordGenerator_ExcludeAlike, m_ui->checkBoxExcludeAlike->isChecked()); config()->set(Config::PasswordGenerator_ExcludeAlike, m_ui->checkBoxExcludeAlike->isChecked());
config()->set(Config::PasswordGenerator_EnsureEvery, m_ui->checkBoxEnsureEvery->isChecked()); config()->set(Config::PasswordGenerator_EnsureEvery, m_ui->checkBoxEnsureEvery->isChecked());
@ -220,15 +231,6 @@ QString PasswordGeneratorWidget::getGeneratedPassword()
return m_ui->editNewPassword->text(); return m_ui->editNewPassword->text();
} }
void PasswordGeneratorWidget::keyPressEvent(QKeyEvent* e)
{
if (e->key() == Qt::Key_Escape && m_standalone) {
emit closePasswordGenerator();
} else {
e->ignore();
}
}
void PasswordGeneratorWidget::regeneratePassword() void PasswordGeneratorWidget::regeneratePassword()
{ {
if (m_ui->tabWidget->currentIndex() == Password) { if (m_ui->tabWidget->currentIndex() == Password) {
@ -273,7 +275,7 @@ void PasswordGeneratorWidget::applyPassword()
{ {
saveSettings(); saveSettings();
emit appliedPassword(m_ui->editNewPassword->text()); emit appliedPassword(m_ui->editNewPassword->text());
emit closePasswordGenerator(); emit closed();
} }
void PasswordGeneratorWidget::copyPassword() void PasswordGeneratorWidget::copyPassword()
@ -534,6 +536,9 @@ void PasswordGeneratorWidget::updateGenerator()
} else { } else {
m_ui->buttonGenerate->setEnabled(false); m_ui->buttonGenerate->setEnabled(false);
} }
m_ui->clearInclude->setVisible(!m_ui->editAdditionalChars->text().isEmpty());
m_ui->clearExclude->setVisible(!m_ui->editExcludedChars->text().isEmpty());
} else { } else {
m_dicewareGenerator->setWordCase( m_dicewareGenerator->setWordCase(
static_cast<PassphraseGenerator::PassphraseWordCase>(m_ui->wordCaseComboBox->currentData().toInt())); static_cast<PassphraseGenerator::PassphraseWordCase>(m_ui->wordCaseComboBox->currentData().toInt()));

View file

@ -64,7 +64,7 @@ public slots:
signals: signals:
void appliedPassword(const QString& password); void appliedPassword(const QString& password);
void closePasswordGenerator(); void closed();
private slots: private slots:
void updateButtonsEnabled(const QString& password); void updateButtonsEnabled(const QString& password);
@ -87,9 +87,6 @@ private:
const QScopedPointer<PasswordGenerator> m_passwordGenerator; const QScopedPointer<PasswordGenerator> m_passwordGenerator;
const QScopedPointer<PassphraseGenerator> m_dicewareGenerator; const QScopedPointer<PassphraseGenerator> m_dicewareGenerator;
const QScopedPointer<Ui::PasswordGeneratorWidget> m_ui; const QScopedPointer<Ui::PasswordGeneratorWidget> m_ui;
protected:
void keyPressEvent(QKeyEvent* e) override;
}; };
#endif // KEEPASSX_PASSWORDGENERATORWIDGET_H #endif // KEEPASSX_PASSWORDGENERATORWIDGET_H

View file

@ -870,9 +870,6 @@ QProgressBar::chunk {
<property name="accessibleName"> <property name="accessibleName">
<string>Additional characters</string> <string>Additional characters</string>
</property> </property>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="1" column="1">
@ -895,9 +892,6 @@ QProgressBar::chunk {
<property name="accessibleName"> <property name="accessibleName">
<string>Excluded characters</string> <string>Excluded characters</string>
</property> </property>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget> </widget>
</item> </item>
<item row="1" column="0"> <item row="1" column="0">
@ -1152,6 +1146,9 @@ QProgressBar::chunk {
<property name="text"> <property name="text">
<string>Close</string> <string>Close</string>
</property> </property>
<property name="shortcut">
<string>Esc</string>
</property>
</widget> </widget>
</item> </item>
<item> <item>
@ -1159,6 +1156,9 @@ QProgressBar::chunk {
<property name="text"> <property name="text">
<string>Apply Password</string> <string>Apply Password</string>
</property> </property>
<property name="shortcut">
<string>Ctrl+S</string>
</property>
<property name="default"> <property name="default">
<bool>true</bool> <bool>true</bool>
</property> </property>
@ -1183,6 +1183,22 @@ QProgressBar::chunk {
</spacer> </spacer>
</item> </item>
</layout> </layout>
<action name="clearInclude">
<property name="text">
<string>Clear</string>
</property>
<property name="toolTip">
<string>Clear</string>
</property>
</action>
<action name="clearExclude">
<property name="text">
<string>Clear</string>
</property>
<property name="toolTip">
<string>Clear</string>
</property>
</action>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget> <customwidget>

View file

@ -185,14 +185,16 @@ QVariant EntryModel::data(const QModelIndex& index, int role) const
} }
return result; return result;
case Notes: case Notes:
// Display only first line of notes in simplified format if not hidden if (!entry->notes().isEmpty()) {
if (config()->get(Config::Security_HideNotes).toBool()) { if (config()->get(Config::Security_HideNotes).toBool()) {
result = EntryModel::HiddenContentDisplay; result = EntryModel::HiddenContentDisplay;
} else { } else {
result = entry->notes().section("\n", 0, 0).simplified(); // Display only first line of notes in simplified format if not hidden
} result = entry->notes().section("\n", 0, 0).simplified();
if (attr->isReference(EntryAttributes::NotesKey)) { }
result.prepend(tr("Ref: ", "Reference abbreviation")); if (attr->isReference(EntryAttributes::NotesKey)) {
result.prepend(tr("Ref: ", "Reference abbreviation"));
}
} }
return result; return result;
case Expires: case Expires:

View file

@ -126,8 +126,9 @@ ReportsWidgetHealthcheck::ReportsWidgetHealthcheck(QWidget* parent)
m_ui->healthcheckTableView->setModel(m_referencesModel.data()); m_ui->healthcheckTableView->setModel(m_referencesModel.data());
m_ui->healthcheckTableView->setSelectionMode(QAbstractItemView::NoSelection); m_ui->healthcheckTableView->setSelectionMode(QAbstractItemView::NoSelection);
m_ui->healthcheckTableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); m_ui->healthcheckTableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
connect(m_ui->healthcheckTableView, SIGNAL(customContextMenuRequested(QPoint)), SLOT(customMenuRequested(QPoint))); m_ui->healthcheckTableView->setSortingEnabled(true);
connect(m_ui->healthcheckTableView, SIGNAL(customContextMenuRequested(QPoint)), SLOT(customMenuRequested(QPoint)));
connect(m_ui->healthcheckTableView, SIGNAL(doubleClicked(QModelIndex)), SLOT(emitEntryActivated(QModelIndex))); connect(m_ui->healthcheckTableView, SIGNAL(doubleClicked(QModelIndex)), SLOT(emitEntryActivated(QModelIndex)));
connect(m_ui->showKnownBadCheckBox, SIGNAL(stateChanged(int)), this, SLOT(calculateHealth())); connect(m_ui->showKnownBadCheckBox, SIGNAL(stateChanged(int)), this, SLOT(calculateHealth()));
} }

View file

@ -43,9 +43,6 @@
<property name="sortingEnabled"> <property name="sortingEnabled">
<bool>false</bool> <bool>false</bool>
</property> </property>
<attribute name="horizontalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="horizontalHeaderStretchLastSection"> <attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool> <bool>true</bool>
</attribute> </attribute>

View file

@ -56,6 +56,7 @@ ReportsWidgetHibp::ReportsWidgetHibp(QWidget* parent)
m_ui->hibpTableView->setModel(m_referencesModel.data()); m_ui->hibpTableView->setModel(m_referencesModel.data());
m_ui->hibpTableView->setSelectionMode(QAbstractItemView::NoSelection); m_ui->hibpTableView->setSelectionMode(QAbstractItemView::NoSelection);
m_ui->hibpTableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); m_ui->hibpTableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
m_ui->hibpTableView->setSortingEnabled(true);
connect(m_ui->hibpTableView, SIGNAL(doubleClicked(QModelIndex)), SLOT(emitEntryActivated(QModelIndex))); connect(m_ui->hibpTableView, SIGNAL(doubleClicked(QModelIndex)), SLOT(emitEntryActivated(QModelIndex)));
connect(m_ui->hibpTableView, SIGNAL(customContextMenuRequested(QPoint)), SLOT(customMenuRequested(QPoint))); connect(m_ui->hibpTableView, SIGNAL(customContextMenuRequested(QPoint)), SLOT(customMenuRequested(QPoint)));

View file

@ -157,9 +157,6 @@
<property name="sortingEnabled"> <property name="sortingEnabled">
<bool>false</bool> <bool>false</bool>
</property> </property>
<attribute name="horizontalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="horizontalHeaderStretchLastSection"> <attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool> <bool>true</bool>
</attribute> </attribute>

View file

@ -233,8 +233,8 @@ namespace
return {}; return {};
} }
default: default:
Q_ASSERT(false); qWarning("Prevented untrusted import of signed KeeShare database %s", qPrintable(reference.path));
return {reference.path, ShareObserver::Result::Error, ShareImport::tr("Unexpected error")}; return {reference.path, ShareObserver::Result::Warning, ShareImport::tr("Untrusted import prevented")};
} }
#endif #endif
} }
@ -323,7 +323,7 @@ namespace
return {}; return {};
} }
default: default:
qWarning("Prevent untrusted import"); qWarning("Prevented untrusted import of unsigned KeeShare database %s", qPrintable(reference.path));
return {reference.path, ShareObserver::Result::Warning, ShareImport::tr("Untrusted import prevented")}; return {reference.path, ShareObserver::Result::Warning, ShareImport::tr("Untrusted import prevented")};
} }
#endif #endif

View file

@ -387,7 +387,7 @@ bool SSHAgent::checkIdentity(const OpenSSHKey& key, bool& loaded)
loaded = false; loaded = false;
for (const auto it : list) { for (const auto& it : list) {
if (*it == key) { if (*it == key) {
loaded = true; loaded = true;
break; break;

View file

@ -189,7 +189,7 @@ void TestGui::testSettingsDefaultTabOrder()
QTest::keyClick(settingsWidget, Qt::Key::Key_Escape); QTest::keyClick(settingsWidget, Qt::Key::Key_Escape);
// check database settings default tab order // check database settings default tab order
triggerAction("actionChangeDatabaseSettings"); triggerAction("actionDatabaseSettings");
auto* dbSettingsWidget = m_mainWindow->findChild<DatabaseSettingsDialog*>(); auto* dbSettingsWidget = m_mainWindow->findChild<DatabaseSettingsDialog*>();
QVERIFY(dbSettingsWidget->isVisible()); QVERIFY(dbSettingsWidget->isVisible());
QCOMPARE(dbSettingsWidget->findChild<CategoryListWidget*>("categoryList")->currentCategory(), 0); QCOMPARE(dbSettingsWidget->findChild<CategoryListWidget*>("categoryList")->currentCategory(), 0);
@ -1257,7 +1257,7 @@ void TestGui::testSave()
void TestGui::testDatabaseSettings() void TestGui::testDatabaseSettings()
{ {
m_db->metadata()->setName("testDatabaseSettings"); m_db->metadata()->setName("testDatabaseSettings");
triggerAction("actionChangeDatabaseSettings"); triggerAction("actionDatabaseSettings");
auto* dbSettingsDialog = m_dbWidget->findChild<QWidget*>("databaseSettingsDialog"); auto* dbSettingsDialog = m_dbWidget->findChild<QWidget*>("databaseSettingsDialog");
auto* transformRoundsSpinBox = dbSettingsDialog->findChild<QSpinBox*>("transformRoundsSpinBox"); auto* transformRoundsSpinBox = dbSettingsDialog->findChild<QSpinBox*>("transformRoundsSpinBox");
auto advancedToggle = dbSettingsDialog->findChild<QCheckBox*>("advancedSettingsToggle"); auto advancedToggle = dbSettingsDialog->findChild<QCheckBox*>("advancedSettingsToggle");