diff --git a/src/fdosecrets/objects/Collection.cpp b/src/fdosecrets/objects/Collection.cpp index 44b0f0361d..8b6190eae4 100644 --- a/src/fdosecrets/objects/Collection.cpp +++ b/src/fdosecrets/objects/Collection.cpp @@ -79,7 +79,7 @@ namespace FdoSecrets return false; } - // populate contents after expose on dbus, because items rely on parent's dbus object path + // populate contents after expose on dbus, because items rely on parent's dbus object path. if (!backendLocked()) { populateContents(); } else { @@ -107,7 +107,7 @@ namespace FdoSecrets DBusResult Collection::ensureUnlocked() const { - if (backendLocked()) { + if (collectionLocked()) { return DBusResult(DBUS_ERROR_SECRET_IS_LOCKED); } return {}; @@ -130,7 +130,7 @@ namespace FdoSecrets return ret; } - if (backendLocked()) { + if (collectionLocked()) { label = name(); } else { label = m_backend->database()->metadata()->name(); @@ -159,7 +159,7 @@ namespace FdoSecrets if (ret.err()) { return ret; } - locked = backendLocked(); + locked = collectionLocked(); return {}; } @@ -219,9 +219,9 @@ namespace FdoSecrets return ret; } - if (backendLocked()) { + if (collectionLocked()) { // searchItems should work, whether `this` is locked or not. - // however, we can't search items the same way as in gnome-keying, + // However, we can't search items the same way as in gnome-keyring, // because there's no database at all when locked. return {}; } @@ -395,7 +395,7 @@ namespace FdoSecrets removeFromDBus(); return; } - emit collectionLockChanged(backendLocked()); + emit collectionLockChanged(collectionLocked()); } void Collection::populateContents() @@ -606,7 +606,9 @@ namespace FdoSecrets } } + m_exposedGroup = nullptr; m_items.clear(); + m_entryToItem.clear(); } QString Collection::backendFilePath() const @@ -621,9 +623,19 @@ namespace FdoSecrets bool Collection::backendLocked() const { + // True when the underlying database is locked, uninitialised, or absent. return !m_backend || !m_backend->database()->isInitialized() || m_backend->isLocked(); } + bool Collection::collectionLocked() const + { + // True when the collection appears locked to DBus clients. + // The collection appears locked when the database is locked, and also while + // m_exposedGroup is null - between the databaseUnlocked signal and the end of + // populateContents(). + return backendLocked() || !m_exposedGroup; + } + bool Collection::doDeleteEntry(Entry* entry) { // Confirm entry removal before moving forward diff --git a/src/fdosecrets/objects/Collection.h b/src/fdosecrets/objects/Collection.h index c8a49ef355..565daf5d21 100644 --- a/src/fdosecrets/objects/Collection.h +++ b/src/fdosecrets/objects/Collection.h @@ -145,6 +145,7 @@ namespace FdoSecrets void cleanupConnections(); bool backendLocked() const; + bool collectionLocked() const; /** * Check if the backend is a valid object, send error reply if not. diff --git a/src/fdosecrets/objects/Service.cpp b/src/fdosecrets/objects/Service.cpp index e3fcefeb5f..e2aa3b5884 100644 --- a/src/fdosecrets/objects/Service.cpp +++ b/src/fdosecrets/objects/Service.cpp @@ -275,7 +275,21 @@ namespace FdoSecrets return ret; } - while (unlockedColls.isEmpty() && settings()->unlockBeforeSearch()) { + auto anyBackendLocked = [this]() { + for (const auto& coll : asConst(m_collections)) { + if (auto* db = coll->backend(); db && db->isLocked()) { + return true; + } + } + return false; + }; + + // unlockedColls.isEmpty() can be true even when no DatabaseWidget is + // locked: a collection that is still being populated counts as locked, + // while its database is already on its way to being unlocked. Don't + // open the unlock dialog in that case - populate finishes on its own + // and the client's next call returns real data. + while (unlockedColls.isEmpty() && settings()->unlockBeforeSearch() && anyBackendLocked()) { // enable compatibility mode by making sure at least one database is unlocked QEventLoop loop; bool wasAccepted = false;