Merge branch 'master' into develop
This commit is contained in:
@@ -322,7 +322,7 @@ QString BrowserService::storeKey(const QString& key)
|
||||
|
||||
do {
|
||||
QInputDialog keyDialog;
|
||||
connect(m_currentDatabaseWidget, SIGNAL(databaseLocked()), &keyDialog, SLOT(reject()));
|
||||
connect(m_currentDatabaseWidget, SIGNAL(databaseLockRequested()), &keyDialog, SLOT(reject()));
|
||||
keyDialog.setWindowTitle(tr("KeePassXC: New key association request"));
|
||||
keyDialog.setLabelText(tr("You have received an association request for the following database:\n%1\n\n"
|
||||
"Give the connection a unique name or ID, for example:\nchrome-laptop.")
|
||||
@@ -778,7 +778,7 @@ QList<Entry*> BrowserService::confirmEntries(QList<Entry*>& pwEntriesToConfirm,
|
||||
updateWindowState();
|
||||
BrowserAccessControlDialog accessControlDialog;
|
||||
|
||||
connect(m_currentDatabaseWidget, SIGNAL(databaseLocked()), &accessControlDialog, SLOT(reject()));
|
||||
connect(m_currentDatabaseWidget, SIGNAL(databaseLockRequested()), &accessControlDialog, SLOT(reject()));
|
||||
|
||||
connect(&accessControlDialog, &BrowserAccessControlDialog::disableAccess, [&](QTableWidgetItem* item) {
|
||||
auto entry = pwEntriesToConfirm[item->row()];
|
||||
|
||||
@@ -36,8 +36,6 @@ const int Entry::ResolveMaximumDepth = 10;
|
||||
const QString Entry::AutoTypeSequenceUsername = "{USERNAME}{ENTER}";
|
||||
const QString Entry::AutoTypeSequencePassword = "{PASSWORD}{ENTER}";
|
||||
|
||||
Entry::CloneFlags Entry::DefaultCloneFlags = Entry::CloneNewUuid | Entry::CloneResetTimeInfo;
|
||||
|
||||
Entry::Entry()
|
||||
: m_attributes(new EntryAttributes(this))
|
||||
, m_attachments(new EntryAttachments(this))
|
||||
|
||||
@@ -161,6 +161,8 @@ public:
|
||||
CloneNewUuid = 1, // generate a random uuid for the clone
|
||||
CloneResetTimeInfo = 2, // set all TimeInfo attributes to the current time
|
||||
CloneIncludeHistory = 4, // clone the history items
|
||||
CloneDefault = CloneNewUuid | CloneResetTimeInfo,
|
||||
CloneCopy = CloneNewUuid | CloneResetTimeInfo | CloneIncludeHistory,
|
||||
CloneRenameTitle = 8, // add "-Clone" after the original title
|
||||
CloneUserAsRef = 16, // Add the user as a reference to the original entry
|
||||
ClonePassAsRef = 32, // Add the password as a reference to the original entry
|
||||
@@ -210,7 +212,6 @@ public:
|
||||
static const int ResolveMaximumDepth;
|
||||
static const QString AutoTypeSequenceUsername;
|
||||
static const QString AutoTypeSequencePassword;
|
||||
static CloneFlags DefaultCloneFlags;
|
||||
|
||||
/**
|
||||
* Creates a duplicate of this entry except that the returned entry isn't
|
||||
@@ -218,7 +219,7 @@ public:
|
||||
* Note that you need to copy the custom icons manually when inserting the
|
||||
* new entry into another database.
|
||||
*/
|
||||
Entry* clone(CloneFlags flags = DefaultCloneFlags) const;
|
||||
Entry* clone(CloneFlags flags = CloneDefault) const;
|
||||
void copyDataFrom(const Entry* other);
|
||||
QString maskPasswordPlaceholders(const QString& str) const;
|
||||
Entry* resolveReference(const QString& str) const;
|
||||
|
||||
@@ -36,9 +36,6 @@ const int Group::DefaultIconNumber = 48;
|
||||
const int Group::RecycleBinIconNumber = 43;
|
||||
const QString Group::RootAutoTypeSequence = "{USERNAME}{TAB}{PASSWORD}{ENTER}";
|
||||
|
||||
Group::CloneFlags Group::DefaultCloneFlags =
|
||||
Group::CloneNewUuid | Group::CloneResetTimeInfo | Group::CloneIncludeEntries;
|
||||
|
||||
Group::Group()
|
||||
: m_customData(new CustomData(this))
|
||||
, m_updateTimeinfo(true)
|
||||
|
||||
@@ -56,6 +56,7 @@ public:
|
||||
CloneNewUuid = 1, // generate a random uuid for the clone
|
||||
CloneResetTimeInfo = 2, // set all TimeInfo attributes to the current time
|
||||
CloneIncludeEntries = 4, // clone the group entries
|
||||
CloneDefault = CloneNewUuid | CloneResetTimeInfo | CloneIncludeEntries,
|
||||
};
|
||||
Q_DECLARE_FLAGS(CloneFlags, CloneFlag)
|
||||
|
||||
@@ -108,7 +109,6 @@ public:
|
||||
|
||||
static const int DefaultIconNumber;
|
||||
static const int RecycleBinIconNumber;
|
||||
static CloneFlags DefaultCloneFlags;
|
||||
static const QString RootAutoTypeSequence;
|
||||
|
||||
Group* findChildByName(const QString& name);
|
||||
@@ -157,8 +157,8 @@ public:
|
||||
QSet<QUuid> customIconsRecursive() const;
|
||||
QList<QString> usernamesRecursive(int topN = -1) const;
|
||||
|
||||
Group* clone(Entry::CloneFlags entryFlags = Entry::DefaultCloneFlags,
|
||||
CloneFlags groupFlags = DefaultCloneFlags) const;
|
||||
Group* clone(Entry::CloneFlags entryFlags = Entry::CloneDefault,
|
||||
Group::CloneFlags groupFlags = Group::CloneDefault) const;
|
||||
|
||||
void copyDataFrom(const Group* other);
|
||||
QString print(bool recursive = false, bool flatten = false, int depth = 0);
|
||||
|
||||
@@ -73,7 +73,7 @@ QString Crypto::debugInfo()
|
||||
Q_ASSERT(Crypto::initialized());
|
||||
|
||||
QString debugInfo = QObject::tr("Cryptographic libraries:").append("\n");
|
||||
debugInfo.append(" libgcrypt ").append(m_backendVersion).append("\n");
|
||||
debugInfo.append("- libgcrypt ").append(m_backendVersion).append("\n");
|
||||
return debugInfo;
|
||||
}
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ static const QString aboutContributors = R"(
|
||||
<li>Kernellinux</li>
|
||||
<li>Micha Ober</li>
|
||||
<li>PublicByte</li>
|
||||
<li>Clayton Casciato</li>
|
||||
</ul>
|
||||
<h3>Notable Code Contributions:</h3>
|
||||
<ul>
|
||||
@@ -86,7 +87,6 @@ static const QString aboutContributors = R"(
|
||||
</ul>
|
||||
<h3>Patreon Supporters:</h3>
|
||||
<ul>
|
||||
<li>Igor Zinovik</li>
|
||||
<li>Alexanderjb</li>
|
||||
<li>Richard Ames</li>
|
||||
<li>SLmanDR</li>
|
||||
@@ -94,7 +94,7 @@ static const QString aboutContributors = R"(
|
||||
<li>Tyler Gass</li>
|
||||
<li>Nuutti Toivola</li>
|
||||
<li>Gregory Werbin</li>
|
||||
<li>Lionel Laské</li>
|
||||
<li>Lionel Laské</li>
|
||||
<li>Ivar</li>
|
||||
<li>Darren</li>
|
||||
<li>Brad</li>
|
||||
|
||||
@@ -59,7 +59,12 @@ void Clipboard::setText(const QString& text, bool clear)
|
||||
clipboard->setMimeData(mime, QClipboard::Clipboard);
|
||||
#else
|
||||
mime->setText(text);
|
||||
#ifdef Q_OS_LINUX
|
||||
mime->setData("x-kde-passwordManagerHint", QByteArrayLiteral("secret"));
|
||||
#endif
|
||||
#ifdef Q_OS_WIN
|
||||
mime->setData("ExcludeClipboardContentFromMonitorProcessing", QByteArrayLiteral("1"));
|
||||
#endif
|
||||
clipboard->setMimeData(mime, QClipboard::Clipboard);
|
||||
|
||||
if (clipboard->supportsSelection()) {
|
||||
|
||||
@@ -20,12 +20,19 @@
|
||||
#include "DatabaseWidget.h"
|
||||
#include "core/Database.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <QtPlatformHeaders/QWindowsWindowFunctions>
|
||||
#endif
|
||||
|
||||
DatabaseOpenDialog::DatabaseOpenDialog(QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, m_view(new DatabaseOpenWidget(this))
|
||||
{
|
||||
setWindowTitle(tr("Unlock Database - KeePassXC"));
|
||||
setWindowFlags(Qt::Dialog | Qt::WindowStaysOnTopHint);
|
||||
#ifdef Q_OS_WIN
|
||||
QWindowsWindowFunctions::setWindowActivationBehavior(QWindowsWindowFunctions::AlwaysActivateWindow);
|
||||
#endif
|
||||
connect(m_view, SIGNAL(dialogFinished(bool)), this, SLOT(complete(bool)));
|
||||
auto* layout = new QVBoxLayout();
|
||||
layout->setMargin(0);
|
||||
|
||||
@@ -165,6 +165,7 @@ void DatabaseOpenWidget::clearForms()
|
||||
m_ui->editPassword->setText("");
|
||||
m_ui->editPassword->setShowPassword(false);
|
||||
m_ui->keyFileLineEdit->clear();
|
||||
m_ui->keyFileLineEdit->setShowPassword(false);
|
||||
m_ui->checkTouchID->setChecked(false);
|
||||
m_ui->challengeResponseCombo->clear();
|
||||
m_db.reset();
|
||||
@@ -380,6 +381,7 @@ void DatabaseOpenWidget::browseKeyFile()
|
||||
void DatabaseOpenWidget::clearKeyFileText()
|
||||
{
|
||||
m_ui->keyFileLineEdit->clear();
|
||||
m_ui->keyFileLineEdit->setShowPassword(false);
|
||||
}
|
||||
|
||||
void DatabaseOpenWidget::pollHardwareKey()
|
||||
|
||||
@@ -406,7 +406,7 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="keyFileLineEdit">
|
||||
<widget class="PasswordEdit" name="keyFileLineEdit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -416,6 +416,9 @@
|
||||
<property name="accessibleName">
|
||||
<string>Key file to unlock the database</string>
|
||||
</property>
|
||||
<property name="echoMode">
|
||||
<enum>QLineEdit::Password</enum>
|
||||
</property>
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
|
||||
@@ -216,7 +216,7 @@ DatabaseWidget::DatabaseWidget(QSharedPointer<Database> db, QWidget* parent)
|
||||
|
||||
#ifdef WITH_XC_SSHAGENT
|
||||
if (sshAgent()->isEnabled()) {
|
||||
connect(this, SIGNAL(databaseLockRequested()), sshAgent(), SLOT(databaseLocked()));
|
||||
connect(this, SIGNAL(databaseLocked()), sshAgent(), SLOT(databaseLocked()));
|
||||
connect(this, SIGNAL(databaseUnlocked()), sshAgent(), SLOT(databaseUnlocked()));
|
||||
}
|
||||
#endif
|
||||
@@ -437,6 +437,7 @@ void DatabaseWidget::showTotp()
|
||||
}
|
||||
|
||||
auto totpDialog = new TotpDialog(this, currentEntry);
|
||||
connect(this, &DatabaseWidget::databaseLockRequested, totpDialog, &TotpDialog::close);
|
||||
totpDialog->open();
|
||||
}
|
||||
|
||||
@@ -460,6 +461,7 @@ void DatabaseWidget::setupTotp()
|
||||
|
||||
auto setupTotpDialog = new TotpSetupDialog(this, currentEntry);
|
||||
connect(setupTotpDialog, SIGNAL(totpUpdated()), SIGNAL(entrySelectionChanged()));
|
||||
connect(this, &DatabaseWidget::databaseLockRequested, setupTotpDialog, &TotpSetupDialog::close);
|
||||
setupTotpDialog->open();
|
||||
}
|
||||
|
||||
@@ -703,6 +705,7 @@ void DatabaseWidget::showTotpKeyQrCode()
|
||||
auto currentEntry = currentSelectedEntry();
|
||||
if (currentEntry) {
|
||||
auto totpDisplayDialog = new TotpExportSettingsDialog(this, currentEntry);
|
||||
connect(this, &DatabaseWidget::databaseLockRequested, totpDisplayDialog, &TotpExportSettingsDialog::close);
|
||||
totpDisplayDialog->open();
|
||||
}
|
||||
}
|
||||
@@ -1533,6 +1536,11 @@ bool DatabaseWidget::lock()
|
||||
|
||||
emit databaseLockRequested();
|
||||
|
||||
// ignore event if we are active and a modal dialog is still open (such as a message box or file dialog)
|
||||
if (isVisible() && QApplication::activeModalWidget()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
clipboard()->clearCopiedText();
|
||||
|
||||
if (isEditWidgetModified()) {
|
||||
|
||||
@@ -74,6 +74,18 @@ void EditWidget::addPage(const QString& labelText, const QIcon& icon, QWidget* w
|
||||
m_ui->categoryList->addCategory(labelText, icon);
|
||||
}
|
||||
|
||||
bool EditWidget::hasPage(QWidget* widget)
|
||||
{
|
||||
for (int i = 0; i < m_ui->stackedWidget->count(); i++) {
|
||||
auto* scrollArea = qobject_cast<QScrollArea*>(m_ui->stackedWidget->widget(i));
|
||||
if (scrollArea && scrollArea->widget() == widget) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void EditWidget::setPageHidden(QWidget* widget, bool hidden)
|
||||
{
|
||||
int index = -1;
|
||||
|
||||
@@ -42,6 +42,7 @@ public:
|
||||
~EditWidget();
|
||||
|
||||
void addPage(const QString& labelText, const QIcon& icon, QWidget* widget);
|
||||
bool hasPage(QWidget* widget);
|
||||
void setPageHidden(QWidget* widget, bool hidden);
|
||||
void setCurrentPage(int index);
|
||||
void setHeadline(const QString& text);
|
||||
|
||||
@@ -286,14 +286,18 @@ void EntryPreviewWidget::updateEntryAdvancedTab()
|
||||
|
||||
setTabEnabled(m_ui->entryTabWidget, m_ui->entryAdvancedTab, hasAttributes || hasAttachments);
|
||||
if (hasAttributes) {
|
||||
QString attributesText;
|
||||
QString attributesText("<table>");
|
||||
for (const QString& key : customAttributes) {
|
||||
QString value = m_currentEntry->attributes()->value(key);
|
||||
QString value;
|
||||
if (m_currentEntry->attributes()->isProtected(key)) {
|
||||
value = "<i>" + tr("[PROTECTED]") + "</i>";
|
||||
} else {
|
||||
value = m_currentEntry->attributes()->value(key).toHtmlEscaped();
|
||||
value.replace('\n', QLatin1String("<br/>"));
|
||||
}
|
||||
attributesText.append(tr("<b>%1</b>: %2", "attributes line").arg(key, value).append("<br/>"));
|
||||
attributesText.append(tr("<tr><td><b>%1</b>:</td><td>%2</td></tr>", "attributes line").arg(key, value));
|
||||
}
|
||||
attributesText.append("</table>");
|
||||
m_ui->entryAttributesEdit->setText(attributesText);
|
||||
}
|
||||
|
||||
@@ -303,6 +307,8 @@ void EntryPreviewWidget::updateEntryAdvancedTab()
|
||||
void EntryPreviewWidget::updateEntryAutotypeTab()
|
||||
{
|
||||
Q_ASSERT(m_currentEntry);
|
||||
|
||||
m_ui->entrySequenceLabel->setText(m_currentEntry->effectiveAutoTypeSequence());
|
||||
m_ui->entryAutotypeTree->clear();
|
||||
QList<QTreeWidgetItem*> items;
|
||||
const AutoTypeAssociations* autotypeAssociations = m_currentEntry->autoTypeAssociations();
|
||||
@@ -314,7 +320,7 @@ void EntryPreviewWidget::updateEntryAutotypeTab()
|
||||
}
|
||||
|
||||
m_ui->entryAutotypeTree->addTopLevelItems(items);
|
||||
setTabEnabled(m_ui->entryTabWidget, m_ui->entryAutotypeTab, !items.isEmpty());
|
||||
setTabEnabled(m_ui->entryTabWidget, m_ui->entryAutotypeTab, m_currentEntry->autoTypeEnabled());
|
||||
}
|
||||
|
||||
void EntryPreviewWidget::updateGroupHeaderLine()
|
||||
|
||||
@@ -705,6 +705,62 @@
|
||||
<string>Autotype</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QWidget" name="entryAutotypeWidget" native="true">
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="entrySequenceTitleLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Default Sequence</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="entrySequenceLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">sequence</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="entryAutotypeTree">
|
||||
<property name="focusPolicy">
|
||||
|
||||
@@ -536,6 +536,11 @@ MainWindow::MainWindow()
|
||||
m_ui->actionGroupDownloadFavicons->setVisible(false);
|
||||
m_ui->actionEntryDownloadIcon->setVisible(false);
|
||||
#endif
|
||||
#ifndef WITH_XC_DOCS
|
||||
m_ui->actionGettingStarted->setVisible(false);
|
||||
m_ui->actionUserGuide->setVisible(false);
|
||||
m_ui->actionKeyboardShortcuts->setVisible(false);
|
||||
#endif
|
||||
|
||||
// clang-format off
|
||||
connect(m_ui->tabWidget, SIGNAL(messageGlobal(QString,MessageWidget::MessageType)),
|
||||
@@ -793,7 +798,9 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
|
||||
m_ui->actionGroupSortDesc->setEnabled(groupSelected && currentGroupHasChildren);
|
||||
m_ui->actionGroupEmptyRecycleBin->setVisible(recycleBinSelected);
|
||||
m_ui->actionGroupEmptyRecycleBin->setEnabled(recycleBinSelected);
|
||||
#ifdef WITH_XC_NETWORKING
|
||||
m_ui->actionGroupDownloadFavicons->setVisible(!recycleBinSelected);
|
||||
#endif
|
||||
m_ui->actionGroupDownloadFavicons->setEnabled(groupSelected && currentGroupHasEntries
|
||||
&& !recycleBinSelected);
|
||||
m_ui->actionDatabaseSecurity->setEnabled(true);
|
||||
@@ -1579,11 +1586,6 @@ void MainWindow::toggleWindow()
|
||||
|
||||
void MainWindow::lockDatabasesAfterInactivity()
|
||||
{
|
||||
// ignore event if a modal dialog is open (such as a message box or file dialog)
|
||||
if (QApplication::activeModalWidget()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_ui->tabWidget->lockDatabases();
|
||||
}
|
||||
|
||||
|
||||
@@ -174,9 +174,9 @@ void PasswordGeneratorWidget::saveSettings()
|
||||
|
||||
config()->set(Config::PasswordGenerator_AdvancedMode, m_ui->buttonAdvancedMode->isChecked());
|
||||
if (m_ui->buttonAdvancedMode->isChecked()) {
|
||||
config()->set(Config::PasswordGenerator_SpecialChars, m_ui->checkBoxSpecialChars->isChecked());
|
||||
} else {
|
||||
config()->set(Config::PasswordGenerator_Logograms, m_ui->checkBoxSpecialChars->isChecked());
|
||||
} else {
|
||||
config()->set(Config::PasswordGenerator_SpecialChars, m_ui->checkBoxSpecialChars->isChecked());
|
||||
}
|
||||
config()->set(Config::PasswordGenerator_Braces, m_ui->checkBoxBraces->isChecked());
|
||||
config()->set(Config::PasswordGenerator_Punctuation, m_ui->checkBoxPunctuation->isChecked());
|
||||
|
||||
@@ -259,9 +259,6 @@ QProgressBar::chunk {
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>20</number>
|
||||
</property>
|
||||
|
||||
@@ -31,10 +31,7 @@ TotpDialog::TotpDialog(QWidget* parent, Entry* entry)
|
||||
, m_ui(new Ui::TotpDialog())
|
||||
, m_entry(entry)
|
||||
{
|
||||
if (!m_entry->hasTotp()) {
|
||||
close();
|
||||
return;
|
||||
}
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
m_ui->setupUi(this);
|
||||
|
||||
@@ -42,14 +39,11 @@ TotpDialog::TotpDialog(QWidget* parent, Entry* entry)
|
||||
resetCounter();
|
||||
updateProgressBar();
|
||||
|
||||
connect(parent, SIGNAL(databaseLocked()), SLOT(close()));
|
||||
connect(&m_totpUpdateTimer, SIGNAL(timeout()), this, SLOT(updateProgressBar()));
|
||||
connect(&m_totpUpdateTimer, SIGNAL(timeout()), this, SLOT(updateSeconds()));
|
||||
m_totpUpdateTimer.start(m_step * 10);
|
||||
updateTotp();
|
||||
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
new QShortcut(QKeySequence(QKeySequence::Copy), this, SLOT(copyToClipboard()));
|
||||
|
||||
m_ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Copy"));
|
||||
|
||||
@@ -59,7 +59,6 @@ TotpExportSettingsDialog::TotpExportSettingsDialog(DatabaseWidget* parent, Entry
|
||||
connect(m_buttonBox, SIGNAL(rejected()), SLOT(close()));
|
||||
connect(m_buttonBox, SIGNAL(accepted()), SLOT(copyToClipboard()));
|
||||
connect(m_timer, SIGNAL(timeout()), SLOT(autoClose()));
|
||||
connect(parent, SIGNAL(lockedDatabase()), SLOT(close()));
|
||||
|
||||
new QShortcut(QKeySequence(QKeySequence::Copy), this, SLOT(copyToClipboard()));
|
||||
|
||||
|
||||
@@ -178,9 +178,6 @@ void EditEntryWidget::setupMain()
|
||||
|
||||
m_mainUi->expirePresets->setMenu(createPresetsMenu());
|
||||
connect(m_mainUi->expirePresets->menu(), SIGNAL(triggered(QAction*)), this, SLOT(useExpiryPreset(QAction*)));
|
||||
|
||||
// HACK: Align username text with other line edits. Qt does not let you do this with an application stylesheet.
|
||||
m_mainUi->usernameComboBox->lineEdit()->setStyleSheet("padding-left: 8px;");
|
||||
}
|
||||
|
||||
void EditEntryWidget::setupAdvanced()
|
||||
@@ -268,9 +265,8 @@ void EditEntryWidget::setupAutoType()
|
||||
#ifdef WITH_XC_BROWSER
|
||||
void EditEntryWidget::setupBrowser()
|
||||
{
|
||||
m_browserUi->setupUi(m_browserWidget);
|
||||
|
||||
if (config()->get(Config::Browser_Enabled).toBool()) {
|
||||
m_browserUi->setupUi(m_browserWidget);
|
||||
addPage(tr("Browser Integration"), icons()->icon("internet-web-browser"), m_browserWidget);
|
||||
m_additionalURLsDataModel->setEntryAttributes(m_entryAttributes);
|
||||
m_browserUi->additionalURLsView->setModel(m_additionalURLsDataModel);
|
||||
@@ -944,28 +940,34 @@ void EditEntryWidget::setForms(Entry* entry, bool restore)
|
||||
#endif
|
||||
|
||||
#ifdef WITH_XC_BROWSER
|
||||
if (m_customData->contains(BrowserService::OPTION_SKIP_AUTO_SUBMIT)) {
|
||||
// clang-format off
|
||||
m_browserUi->skipAutoSubmitCheckbox->setChecked(m_customData->value(BrowserService::OPTION_SKIP_AUTO_SUBMIT) == TRUE_STR);
|
||||
// clang-format on
|
||||
} else {
|
||||
m_browserUi->skipAutoSubmitCheckbox->setChecked(false);
|
||||
}
|
||||
if (config()->get(Config::Browser_Enabled).toBool()) {
|
||||
if (!hasPage(m_browserWidget)) {
|
||||
setupBrowser();
|
||||
}
|
||||
|
||||
if (m_customData->contains(BrowserService::OPTION_HIDE_ENTRY)) {
|
||||
m_browserUi->hideEntryCheckbox->setChecked(m_customData->value(BrowserService::OPTION_HIDE_ENTRY) == TRUE_STR);
|
||||
} else {
|
||||
m_browserUi->hideEntryCheckbox->setChecked(false);
|
||||
}
|
||||
if (m_customData->contains(BrowserService::OPTION_SKIP_AUTO_SUBMIT)) {
|
||||
// clang-format off
|
||||
m_browserUi->skipAutoSubmitCheckbox->setChecked(m_customData->value(BrowserService::OPTION_SKIP_AUTO_SUBMIT) == TRUE_STR);
|
||||
// clang-format on
|
||||
} else {
|
||||
m_browserUi->skipAutoSubmitCheckbox->setChecked(false);
|
||||
}
|
||||
|
||||
if (m_customData->contains(BrowserService::OPTION_ONLY_HTTP_AUTH)) {
|
||||
m_browserUi->onlyHttpAuthCheckbox->setChecked(m_customData->value(BrowserService::OPTION_ONLY_HTTP_AUTH)
|
||||
== TRUE_STR);
|
||||
} else {
|
||||
m_browserUi->onlyHttpAuthCheckbox->setChecked(false);
|
||||
}
|
||||
if (m_customData->contains(BrowserService::OPTION_HIDE_ENTRY)) {
|
||||
m_browserUi->hideEntryCheckbox->setChecked(m_customData->value(BrowserService::OPTION_HIDE_ENTRY)
|
||||
== TRUE_STR);
|
||||
} else {
|
||||
m_browserUi->hideEntryCheckbox->setChecked(false);
|
||||
}
|
||||
|
||||
if (m_customData->contains(BrowserService::OPTION_NOT_HTTP_AUTH)) {
|
||||
if (m_customData->contains(BrowserService::OPTION_ONLY_HTTP_AUTH)) {
|
||||
m_browserUi->onlyHttpAuthCheckbox->setChecked(m_customData->value(BrowserService::OPTION_ONLY_HTTP_AUTH)
|
||||
== TRUE_STR);
|
||||
} else {
|
||||
m_browserUi->onlyHttpAuthCheckbox->setChecked(false);
|
||||
}
|
||||
|
||||
if (m_customData->contains(BrowserService::OPTION_NOT_HTTP_AUTH)) {
|
||||
m_browserUi->notHttpAuthCheckbox->setChecked(m_customData->value(BrowserService::OPTION_NOT_HTTP_AUTH)
|
||||
== TRUE_STR);
|
||||
} else {
|
||||
@@ -977,9 +979,12 @@ void EditEntryWidget::setForms(Entry* entry, bool restore)
|
||||
m_browserUi->editURLButton->setEnabled(false);
|
||||
m_browserUi->additionalURLsView->setEditTriggers(editTriggers);
|
||||
|
||||
if (m_additionalURLsDataModel->rowCount() != 0) {
|
||||
m_browserUi->additionalURLsView->setCurrentIndex(m_additionalURLsDataModel->index(0, 0));
|
||||
if (m_additionalURLsDataModel->rowCount() != 0) {
|
||||
m_browserUi->additionalURLsView->setCurrentIndex(m_additionalURLsDataModel->index(0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
setPageHidden(m_browserWidget, !config()->get(Config::Browser_Enabled).toBool());
|
||||
#endif
|
||||
|
||||
m_editWidgetProperties->setFields(entry->timeInfo(), entry->uuid());
|
||||
@@ -1013,6 +1018,15 @@ bool EditEntryWidget::commitEntry()
|
||||
return true;
|
||||
}
|
||||
|
||||
// HACK: Check that entry pointer is still valid, see https://github.com/keepassxreboot/keepassxc/issues/5722
|
||||
if (!m_entry) {
|
||||
QMessageBox::information(this,
|
||||
tr("Invalid Entry"),
|
||||
tr("An external merge operation has invalidated this entry.\n"
|
||||
"Unfortunately, any changes made have been lost."));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check Auto-Type validity early
|
||||
if (!AutoType::verifyAutoTypeSyntax(m_autoTypeUi->sequenceEdit->text())) {
|
||||
return false;
|
||||
|
||||
@@ -262,13 +262,13 @@ bool GroupModel::dropMimeData(const QMimeData* data,
|
||||
targetDb->metadata()->copyCustomIcons(customIcons, sourceDb->metadata());
|
||||
|
||||
// Always clone the group across db's to reset UUIDs
|
||||
group = dragGroup->clone();
|
||||
group = dragGroup->clone(Entry::CloneDefault | Entry::CloneIncludeHistory);
|
||||
if (action == Qt::MoveAction) {
|
||||
// Remove the original group from the sourceDb
|
||||
delete dragGroup;
|
||||
}
|
||||
} else if (action == Qt::CopyAction) {
|
||||
group = dragGroup->clone();
|
||||
group = dragGroup->clone(Entry::CloneCopy);
|
||||
}
|
||||
|
||||
group->setParent(parentGroup, row);
|
||||
@@ -303,13 +303,13 @@ bool GroupModel::dropMimeData(const QMimeData* data,
|
||||
targetDb->metadata()->addCustomIcon(customIcon, sourceDb->metadata()->customIcon(customIcon));
|
||||
}
|
||||
|
||||
// Always clone the entry across db's to reset the UUID
|
||||
entry = dragEntry->clone();
|
||||
// Reset the UUID when moving across db boundary
|
||||
entry = dragEntry->clone(Entry::CloneDefault | Entry::CloneIncludeHistory);
|
||||
if (action == Qt::MoveAction) {
|
||||
delete dragEntry;
|
||||
}
|
||||
} else if (action == Qt::CopyAction) {
|
||||
entry = dragEntry->clone();
|
||||
entry = dragEntry->clone(Entry::CloneCopy);
|
||||
}
|
||||
|
||||
entry->setGroup(parentGroup);
|
||||
|
||||
@@ -127,10 +127,12 @@ void NixUtils::setLaunchAtStartup(bool enable)
|
||||
<< QStringLiteral("StartupNotify=true") << '\n'
|
||||
<< QStringLiteral("Terminal=false") << '\n'
|
||||
<< QStringLiteral("Type=Application") << '\n'
|
||||
<< QStringLiteral("Version=1.0") << "true" << '\n'
|
||||
<< QStringLiteral("Version=1.0") << '\n'
|
||||
<< QStringLiteral("Categories=Utility;Security;Qt;") << '\n'
|
||||
<< QStringLiteral("MimeType=application/x-keepass2;") << '\n'
|
||||
<< QStringLiteral("X-GNOME-Autostart-enabled=true") << endl;
|
||||
<< QStringLiteral("X-GNOME-Autostart-enabled=true") << '\n'
|
||||
<< QStringLiteral("X-GNOME-Autostart-Delay=2") << '\n'
|
||||
<< QStringLiteral("X-KDE-autostart-after=panel") << endl;
|
||||
desktopFile.close();
|
||||
} else if (isLaunchAtStartupEnabled()) {
|
||||
QFile::remove(getAutostartDesktopFilename());
|
||||
|
||||
@@ -58,7 +58,8 @@ namespace
|
||||
// Get average password length
|
||||
int averagePwdLength() const
|
||||
{
|
||||
return m_passwords.empty() ? 0 : pwdTotalLen / m_passwords.size();
|
||||
const auto nPwds = nPwdsUnique + nPwdsReused;
|
||||
return nPwds == 0 ? 0 : std::round(pwdTotalLen / double(nPwds));
|
||||
}
|
||||
|
||||
// Get max number of password reuse (=how many entries
|
||||
|
||||
@@ -4766,7 +4766,11 @@ QRect BaseStyle::subElementRect(SubElement sr, const QStyleOption* opt, const QW
|
||||
}
|
||||
case SE_LineEditContents: {
|
||||
QRect r = QCommonStyle::subElementRect(sr, opt, w);
|
||||
int pad = Phantom::dpiScaled(Phantom::LineEdit_ContentsHPad);
|
||||
int pad = Phantom::LineEdit_ContentsHPad;
|
||||
if (w && qobject_cast<const QComboBox*>(w->parentWidget())) {
|
||||
pad += 3;
|
||||
}
|
||||
pad = Phantom::dpiScaled(pad);
|
||||
return r.adjusted(pad, 0, -pad, 0);
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -13,3 +13,7 @@ DatabaseWidget #SearchBanner, DatabaseWidget #KeeShareBanner {
|
||||
border: 1px solid rgb(190, 190, 190);
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
QLineEdit {
|
||||
padding-left: 2px;
|
||||
}
|
||||
|
||||
@@ -186,23 +186,29 @@ void ShareObserver::handleDatabaseChanged()
|
||||
|
||||
void ShareObserver::handleFileUpdated(const QString& path)
|
||||
{
|
||||
const Result result = importShare(path);
|
||||
if (!result.isValid()) {
|
||||
return;
|
||||
if (!m_inFileUpdate) {
|
||||
QTimer::singleShot(100, this, [this, path] {
|
||||
const Result result = importShare(path);
|
||||
m_inFileUpdate = false;
|
||||
if (!result.isValid()) {
|
||||
return;
|
||||
}
|
||||
QStringList success;
|
||||
QStringList warning;
|
||||
QStringList error;
|
||||
if (result.isError()) {
|
||||
error << tr("Import from %1 failed (%2)").arg(result.path, result.message);
|
||||
} else if (result.isWarning()) {
|
||||
warning << tr("Import from %1 failed (%2)").arg(result.path, result.message);
|
||||
} else if (result.isInfo()) {
|
||||
success << tr("Import from %1 successful (%2)").arg(result.path, result.message);
|
||||
} else {
|
||||
success << tr("Imported from %1").arg(result.path);
|
||||
}
|
||||
notifyAbout(success, warning, error);
|
||||
});
|
||||
m_inFileUpdate = true;
|
||||
}
|
||||
QStringList success;
|
||||
QStringList warning;
|
||||
QStringList error;
|
||||
if (result.isError()) {
|
||||
error << tr("Import from %1 failed (%2)").arg(result.path, result.message);
|
||||
} else if (result.isWarning()) {
|
||||
warning << tr("Import from %1 failed (%2)").arg(result.path, result.message);
|
||||
} else if (result.isInfo()) {
|
||||
success << tr("Import from %1 successful (%2)").arg(result.path, result.message);
|
||||
} else {
|
||||
success << tr("Imported from %1").arg(result.path);
|
||||
}
|
||||
notifyAbout(success, warning, error);
|
||||
}
|
||||
|
||||
ShareObserver::Result ShareObserver::importShare(const QString& path)
|
||||
|
||||
@@ -83,6 +83,7 @@ private:
|
||||
QMap<QPointer<Group>, KeeShareSettings::Reference> m_groupToReference;
|
||||
QMap<QString, QPointer<Group>> m_shareToGroup;
|
||||
QMap<QString, QSharedPointer<FileWatcher>> m_fileWatchers;
|
||||
bool m_inFileUpdate = false;
|
||||
};
|
||||
|
||||
#endif // KEEPASSXC_SHAREOBSERVER_H
|
||||
|
||||
Reference in New Issue
Block a user