diff --git a/src/fdosecrets/objects/Collection.cpp b/src/fdosecrets/objects/Collection.cpp index c826c1db0..30a8f2d0c 100644 --- a/src/fdosecrets/objects/Collection.cpp +++ b/src/fdosecrets/objects/Collection.cpp @@ -328,7 +328,11 @@ namespace FdoSecrets // when creation finishes in backend, we will already have item item = m_entryToItem.value(entry, nullptr); - Q_ASSERT(item); + + if (!item) { + // may happen if entry somehow ends up in recycle bin + return DBusReturn<>::Error(QStringLiteral(DBUS_ERROR_SECRET_NO_SUCH_OBJECT)); + } } ret = item->setProperties(properties); @@ -439,7 +443,7 @@ namespace FdoSecrets auto newUuid = FdoSecrets::settings()->exposedGroup(m_backend->database()); auto newGroup = m_backend->database()->rootGroup()->findGroupByUuid(newUuid); - if (!newGroup) { + if (!newGroup || inRecycleBin(newGroup)) { // no exposed group, delete self doDelete(); return; @@ -451,10 +455,11 @@ namespace FdoSecrets m_exposedGroup = newGroup; // Attach signal to update exposed group settings if the group was removed. + // // The lifetime of the connection is bound to the database object, because - // in Database::~Database, groups are also deleted, but we don't want to - // trigger this. - // This rely on the fact that QObject disconnects signals BEFORE deleting + // in Database::~Database, groups are also deleted as children, but we don't + // want to trigger this. + // This works because the fact that QObject disconnects signals BEFORE deleting // children. QPointer db = m_backend->database().data(); connect(m_exposedGroup.data(), &Group::groupAboutToRemove, db, [db](Group* toBeRemoved) { @@ -468,6 +473,13 @@ namespace FdoSecrets FdoSecrets::settings()->setExposedGroup(db, {}); } }); + // Another possibility is the group being moved to recycle bin. + connect(m_exposedGroup.data(), &Group::groupModified, this, [this]() { + if (inRecycleBin(m_exposedGroup->parentGroup())) { + // reset the exposed group to none + FdoSecrets::settings()->setExposedGroup(m_backend->database().data(), {}); + } + }); // Monitor exposed group settings connect(m_backend->database()->metadata()->customData(), &CustomData::customDataModified, this, [this]() { @@ -646,17 +658,21 @@ namespace FdoSecrets { Q_ASSERT(m_backend); - if (!m_backend->database()->metadata()->recycleBin()) { + if (!group) { + // just to be safe + return true; + } + + if (!m_backend->database()->metadata()) { return false; } - while (group) { - if (group->uuid() == m_backend->database()->metadata()->recycleBin()->uuid()) { - return true; - } - group = group->parentGroup(); + auto recycleBin = m_backend->database()->metadata()->recycleBin(); + if (!recycleBin) { + return false; } - return false; + + return group->uuid() == recycleBin->uuid() || group->isRecycled(); } bool Collection::inRecycleBin(Entry* entry) const diff --git a/src/fdosecrets/widgets/DatabaseSettingsWidgetFdoSecrets.cpp b/src/fdosecrets/widgets/DatabaseSettingsWidgetFdoSecrets.cpp index fadd01542..16a780de7 100644 --- a/src/fdosecrets/widgets/DatabaseSettingsWidgetFdoSecrets.cpp +++ b/src/fdosecrets/widgets/DatabaseSettingsWidgetFdoSecrets.cpp @@ -85,7 +85,7 @@ protected: // can not call mapFromSource, which internally calls filterAcceptsRow auto group = groupFromSourceIndex(source_idx); - return group->uuid() != recycleBin->uuid(); + return group && !group->isRecycled() && group->uuid() != recycleBin->uuid(); } }; @@ -118,8 +118,13 @@ void DatabaseSettingsWidgetFdoSecrets::loadSettings(QSharedPointer db) m_model.reset(new GroupModelNoRecycle(m_db.data())); m_ui->selectGroup->setModel(m_model.data()); + Group* recycleBin = nullptr; + if (m_db->metadata() && m_db->metadata()->recycleBin()) { + recycleBin = m_db->metadata()->recycleBin(); + } + auto group = m_db->rootGroup()->findGroupByUuid(FdoSecrets::settings()->exposedGroup(m_db)); - if (!group) { + if (!group || group->isRecycled() || (recycleBin && group->uuid() == recycleBin->uuid())) { m_ui->radioDonotExpose->setChecked(true); } else { auto idx = m_model->indexFromGroup(group);