From bcc81b069bb63142ef3f9e28c8ebea83b38533e5 Mon Sep 17 00:00:00 2001 From: Xavier Valls Date: Thu, 29 Apr 2021 10:01:57 +0200 Subject: [PATCH] allow for better granularity when choosing password extension Switches presets for quantity and unit of time pickers. Stores auto extension on modification data as custom data for the entry to respect the spec --- src/core/Entry.cpp | 15 ++++++++ src/core/Entry.h | 2 ++ src/core/TimeDelta.cpp | 10 ++++++ src/core/TimeDelta.h | 2 ++ src/gui/entry/EditEntryWidget.cpp | 53 ++++++++++++++++++++++++---- src/gui/entry/EditEntryWidget.h | 3 +- src/gui/entry/EditEntryWidgetMain.ui | 29 ++++++++++++--- 7 files changed, 101 insertions(+), 13 deletions(-) diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp index 49beb1e9e..62d2b567b 100644 --- a/src/core/Entry.cpp +++ b/src/core/Entry.cpp @@ -23,6 +23,7 @@ #include "core/Group.h" #include "core/Metadata.h" #include "core/PasswordHealth.h" +#include "core/TimeDelta.h" #include "core/Tools.h" #include "totp/totp.h" @@ -727,6 +728,20 @@ void Entry::setExpiryTime(const QDateTime& dateTime) } } +void Entry::setExtendsExpirationOnPwdChange(const bool& value) +{ + if (m_customData->value("ExpirationExtension").toInt() != value) { + m_customData->set("ExpirationExtension", QString::number(value)); + emit entryModified(); + } +} + +void Entry::setExpirationExtension(const QString& quantity, const QString& magnitude) +{ + m_customData->set("ExpirationExtensionQuantity", quantity); + m_customData->set("ExpirationExtensionMagnitude", magnitude); +} + QList Entry::historyItems() { return m_history; diff --git a/src/core/Entry.h b/src/core/Entry.h index 88a89761a..3b7dd2018 100644 --- a/src/core/Entry.h +++ b/src/core/Entry.h @@ -151,6 +151,8 @@ public: void setDefaultAttribute(const QString& attribute, const QString& value); void setExpires(const bool& value); void setExpiryTime(const QDateTime& dateTime); + void setExtendsExpirationOnPwdChange(const bool& value); + void setExpirationExtension(const QString& quantity, const QString& magnitude); void setTotp(QSharedPointer settings); QList historyItems(); diff --git a/src/core/TimeDelta.cpp b/src/core/TimeDelta.cpp index a5331736c..0c172bc78 100644 --- a/src/core/TimeDelta.cpp +++ b/src/core/TimeDelta.cpp @@ -53,6 +53,16 @@ TimeDelta::TimeDelta(int days, int months, int years) { } +TimeDelta TimeDelta::operator*(unsigned int n) +{ + return TimeDelta(n * m_days, n * m_months, n * m_years); +} + +bool TimeDelta::operator==(const TimeDelta& tD) const +{ + return m_days == tD.getDays() && m_years == tD.getYears() && m_months == tD.getMonths(); +} + int TimeDelta::getDays() const { return m_days; diff --git a/src/core/TimeDelta.h b/src/core/TimeDelta.h index d52ba72e5..325fadc05 100644 --- a/src/core/TimeDelta.h +++ b/src/core/TimeDelta.h @@ -34,6 +34,8 @@ public: TimeDelta(); TimeDelta(int days, int months, int years); + TimeDelta operator*(unsigned n); + bool operator==(const TimeDelta& tD) const; int getDays() const; int getMonths() const; diff --git a/src/gui/entry/EditEntryWidget.cpp b/src/gui/entry/EditEntryWidget.cpp index 0b7f81163..8f8aa3301 100644 --- a/src/gui/entry/EditEntryWidget.cpp +++ b/src/gui/entry/EditEntryWidget.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include "autotype/AutoType.h" #include "core/Clock.h" @@ -66,9 +67,18 @@ #include "gui/entry/EntryAttributesModel.h" #include "gui/entry/EntryHistoryModel.h" +QString timeDelta2Text(const TimeDelta& tD) +{ + if (tD.getDays()) { + return "day(s)"; + } + return tD.getMonths() ? "month(s)" : "year(s)"; +}; + EditEntryWidget::EditEntryWidget(QWidget* parent) : EditWidget(parent) , m_entry(nullptr) + , m_extensionOnPwUpdate(std::make_tuple(0, TimeDelta(1, 0, 0))) , m_mainUi(new Ui::EditEntryWidgetMain()) , m_advancedUi(new Ui::EditEntryWidgetAdvanced()) , m_autoTypeUi(new Ui::EditEntryWidgetAutoType()) @@ -178,16 +188,22 @@ void EditEntryWidget::setupMain() m_mainUi->expirePresets->setMenu(createPresetsMenu()); connect(m_mainUi->expirePresets->menu(), SIGNAL(triggered(QAction*)), this, SLOT(useExpiryPreset(QAction*))); - m_mainUi->extendPresets->setMenu(createPresetsMenu()); - connect(m_mainUi->extendPresets->menu(), &QMenu::triggered, this, [&](QAction* action) { - m_extensionOnPwUpdate = action->data().value(); + m_mainUi->extendByMagnitude->setMenu(createExtendByMenu()); + connect(m_mainUi->extendByMagnitude->menu(), &QMenu::triggered, this, [&](QAction* action) { + std::get<1>(m_extensionOnPwUpdate) = action->data().value(); + m_mainUi->extendByMagnitude->setText(action->text()); + setModified(true); + }); + connect(m_mainUi->extendByQuantity, QOverload::of(&QSpinBox::valueChanged), this, [&](int n) { + std::get<0>(m_extensionOnPwUpdate) = static_cast(n); }); connect(m_mainUi->autoExtendExpire, &QCheckBox::toggled, [&](bool enabled) { - m_mainUi->extendPresets->setEnabled(enabled); + m_mainUi->extendByQuantity->setEnabled(enabled); + m_mainUi->extendByMagnitude->setEnabled(enabled); }); connect(m_mainUi->passwordEdit, &QLineEdit::textChanged, this, [&]() { - if (m_mainUi->extendPresets->isEnabled()) { - TimeDelta delta = m_extensionOnPwUpdate; + if (m_mainUi->autoExtendExpire->isEnabled()) { + TimeDelta delta = std::get<1>(m_extensionOnPwUpdate) * std::get<0>(m_extensionOnPwUpdate); QDateTime now = Clock::currentDateTime(); QDateTime expiryDateTime = now + delta; m_mainUi->expireDatePicker->setDateTime(expiryDateTime); @@ -450,7 +466,9 @@ void EditEntryWidget::setupEntryUpdate() #endif connect(m_mainUi->expireCheck, SIGNAL(stateChanged(int)), this, SLOT(setModified())); connect(m_mainUi->expireDatePicker, SIGNAL(dateTimeChanged(QDateTime)), this, SLOT(setModified())); + connect(m_mainUi->autoExtendExpire, SIGNAL(stateChanged(int)), this, SLOT(setModified())); connect(m_mainUi->notesEdit, SIGNAL(textChanged()), this, SLOT(setModified())); + connect(m_mainUi->extendByQuantity, SIGNAL(valueChanged(int)), this, SLOT(setModified())); // Advanced tab connect(m_advancedUi->attributesEdit, SIGNAL(textChanged()), this, SLOT(setModified())); @@ -855,6 +873,7 @@ void EditEntryWidget::setForms(Entry* entry, bool restore) m_mainUi->passwordEdit->setReadOnly(m_history); m_mainUi->expireCheck->setEnabled(!m_history); m_mainUi->expireDatePicker->setReadOnly(m_history); + m_mainUi->autoExtendExpire->setEnabled(!m_history); m_mainUi->notesEnabled->setChecked(!config()->get(Config::Security_HideNotes).toBool()); m_mainUi->notesEdit->setReadOnly(m_history); m_mainUi->notesEdit->setVisible(!config()->get(Config::Security_HideNotes).toBool()); @@ -897,6 +916,12 @@ void EditEntryWidget::setForms(Entry* entry, bool restore) m_mainUi->expireCheck->setChecked(entry->timeInfo().expires()); m_mainUi->expireDatePicker->setDateTime(entry->timeInfo().expiryTime().toLocalTime()); m_mainUi->expirePresets->setEnabled(!m_history); + m_mainUi->autoExtendExpire->setChecked(entry->timeInfo().expires()); + m_mainUi->autoExtendExpire->setChecked(entry->customData()->value("ExpirationExtension").toInt()); + m_mainUi->extendByQuantity->setEnabled(m_mainUi->autoExtendExpire->isChecked()); + m_mainUi->extendByQuantity->setValue(entry->customData()->value("ExpirationExtensionQuantity").toInt()); + m_mainUi->extendByMagnitude->setEnabled(m_mainUi->autoExtendExpire->isChecked()); + m_mainUi->extendByMagnitude->setText(entry->customData()->value("ExpirationExtensionMagnitude")); QList commonUsernames = m_db->commonUsernames(); m_usernameCompleterModel->setStringList(commonUsernames); @@ -1137,7 +1162,9 @@ void EditEntryWidget::updateEntryData(Entry* entry) const entry->setPassword(m_mainUi->passwordEdit->text()); entry->setExpires(m_mainUi->expireCheck->isChecked()); entry->setExpiryTime(m_mainUi->expireDatePicker->dateTime().toUTC()); - + entry->setExtendsExpirationOnPwdChange(m_mainUi->autoExtendExpire->isChecked()); + entry->setExpirationExtension(QString::number(std::get<0>(m_extensionOnPwUpdate)), + timeDelta2Text(std::get<1>(m_extensionOnPwUpdate))); entry->setNotes(m_mainUi->notesEdit->toPlainText()); if (entry->excludeFromReports() != m_advancedUi->excludeReportsCheckBox->isChecked()) { @@ -1541,6 +1568,18 @@ QMenu* EditEntryWidget::createPresetsMenu() return expirePresetsMenu; } +QMenu* EditEntryWidget::createExtendByMenu() +{ + auto* expirePresetsMenu = new QMenu(this); + auto tD = TimeDelta::fromDays(1); + expirePresetsMenu->addAction(timeDelta2Text(tD))->setData(QVariant::fromValue(tD)); + tD = TimeDelta::fromMonths(1); + expirePresetsMenu->addAction(timeDelta2Text(tD))->setData(QVariant::fromValue(tD)); + tD = TimeDelta::fromYears(1); + expirePresetsMenu->addAction(timeDelta2Text(tD))->setData(QVariant::fromValue(tD)); + return expirePresetsMenu; +} + void EditEntryWidget::setupColorButton(bool foreground, const QColor& color) { QWidget* button = m_advancedUi->fgColorButton; diff --git a/src/gui/entry/EditEntryWidget.h b/src/gui/entry/EditEntryWidget.h index c0abe6cb4..af212acb3 100644 --- a/src/gui/entry/EditEntryWidget.h +++ b/src/gui/entry/EditEntryWidget.h @@ -153,6 +153,7 @@ private: bool passwordsEqual(); void setForms(Entry* entry, bool restore = false); QMenu* createPresetsMenu(); + QMenu* createExtendByMenu(); void updateEntryData(Entry* entry) const; #ifdef WITH_XC_SSHAGENT bool getOpenSSHKey(OpenSSHKey& key, bool decrypt = false); @@ -163,7 +164,7 @@ private: QPointer m_entry; QSharedPointer m_db; - TimeDelta m_extensionOnPwUpdate; + std::tuple m_extensionOnPwUpdate; bool m_create; bool m_history; #ifdef WITH_XC_SSHAGENT diff --git a/src/gui/entry/EditEntryWidgetMain.ui b/src/gui/entry/EditEntryWidgetMain.ui index e028792e0..7b05360d8 100644 --- a/src/gui/entry/EditEntryWidgetMain.ui +++ b/src/gui/entry/EditEntryWidgetMain.ui @@ -279,8 +279,6 @@ - - Toggle auto updating expiration @@ -289,12 +287,33 @@ Toggle auto updating expiration date - Automatically extend expiration date on password modification by + Auto assign new password expiration after modification: + + + + 1 + - + + + false + + + 0 + + + 1000 + + + 5 + + + + + false @@ -311,7 +330,7 @@ Expiration extension presets - Time + Time period