Skip to content

LibSecret Map Lookup - #301

Open
Vortelf wants to merge 2 commits into
frankosterfeld:mainfrom
Vortelf:fix/map-lookup
Open

LibSecret Map Lookup#301
Vortelf wants to merge 2 commits into
frankosterfeld:mainfrom
Vortelf:fix/map-lookup

Conversation

@Vortelf

@Vortelf Vortelf commented Jun 23, 2026

Copy link
Copy Markdown

If a Binary-mode lookup would fall through, switch to Text mode and re-invoke secret_password_lookup_fn requesting type map so libsecret can return binary entries encoded as maps.

I found this bug after switching to use Quickshell while continuing to use KWallet as my keychain.

NetworkManager had my passwords stored in KWallet as map since I was using KDE6 previosly. Since the DE I'm using now doesn't advertise as any of the defined in the enum, the program was going through the default LibSecret case. While LibSecret can work with KWallet, it didn't had a case to look for map type of passwords in the keyring, only text and base64.

I saw that with the latest commit, map support was introduced, so hopefully this will be helpful addition.

Also I'm currently using those changes, so it'll be convenient to not have to patch each new version.

@michaelk83

Copy link
Copy Markdown

libsecret, which is a front-end for the Secret Service API, doesn't have a "map" concept at all. That's a concept unique to the legacy KWallet API. However, KWallet knows how to speak Secret Service, and should translate maps entries correctly internally. No further changes should be necessary for that end in QtKeychain, AFAIK.

I saw that with the latest commit, map support was introduced

That was specifically for the legacy KWallet API backend of QtKeychain. This was needed in plasma-nm!551 for the use case when the KWallet API backend remains active:

  • plasma-nm before !551 used to talk directly to the legacy KWallet API (and use its Map type).
  • plasma-nm after !551 talks to QtKeyChain. If QtKeyChain uses the legacy KWallet API, then it needs to be able to read Maps through that particular API.
  • But if QtKeyChain uses the Secret Service API (libsecret backend), then it should be able to read things as is via KWallet's internal translation of maps to the Secret Service API.

@michaelk83

Copy link
Copy Markdown

Hmm.. on closer look at the KWallet code:

  1. KWalletD::writeMap() calls writeEntry() with type Map.
  2. KWalletD::writeEntry() with type Map converts it to JSON and calls writeRawJson().
  3. Which in turn calls m_backend->writeEntry() with type Map.
  4. The backend sets the map content type as text/plain, but saves the type attribute as "map".

So indeed, searching for only type="plaintext" or type="base64" wouldn't find KWallet's type=map entries. So a fallback search is needed, but I'd rather not leak the legacy KWallet-specific "map" concept to the generic libsecret backend or even wider ReadPasswordJob API. Can we do this without introducing an explicit Map type in the public API?

The type="map" search should just return the text or binary value as is, based on the entry content type. For KWallet maps, that should always be text/plain JSON.

Comment thread qtkeychain/keychain.cpp Outdated
Comment on lines +141 to +151
QVariantMap ReadPasswordJob::mapData() const
{
if (d->mode != JobPrivate::Map)
return QVariantMap();

const QJsonDocument doc = QJsonDocument::fromJson(d->data);
if (!doc.isObject())
return QVariantMap();

return doc.object().toVariantMap();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

plasma-nm expects JSON text from type="map" entries when the KWallet backend is active:
https://invent.kde.org/plasma/plasma-nm/-/blob/master/kded/secretagent.cpp#L384
https://github.com/frankosterfeld/qtkeychain/blob/main/qtkeychain/keychain_unix.cpp#L450-L463

It should receive the same with the libsecret backend. And it should be returned from textData(). Please remove the mapData() interface.

Refer to #294 for the full changes on the KWallet backend.

Comment thread qtkeychain/keychain.h Outdated
Comment on lines +197 to +203
enum EntryType { Text = 0, Binary, Map };

/**
* @return The type of data stored for this job's key().
* @see Job::key()
*/
EntryType entryType() const;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove. We should not introduce the backend-specific, legacy "map" concept to the generic public API. Further, the clients should already know what data type they're expecting from their entry.

(Note that the Map type that was added in #294 is hidden in the private implementation class.)

If a Binary-mode lookup would fall through, switch to Text mode and
re-invoke secret_password_lookup_fn requesting type "map" so libsecret
can return binary entries encoded as maps

Address review: keep map lookup internal to libsecret

Remove EntryType, entryType(), and mapData() from the public API.
KWallet map entries found via libsecret are returned as JSON text
through textData(), matching the KWallet backend behavior expected
by plasma-nm.

Co-authored-by: TradeCacheAI <TradeCacheAI@users.noreply.github.com>
@Vortelf

Vortelf commented Jun 24, 2026

Copy link
Copy Markdown
Author

I reverted the changes to what I had initially, to be as simple addition as possible. I had no idea that map is actually legacy, as it doesn't make sense to me given the other two types.

@michaelk83

Copy link
Copy Markdown

QtKeyChain has always only had Text and Binary data. The Secret Service API also has no concept of "maps" and doesn't care about any custom "type" attribute. That concept came from the legacy KWallet API, which is on its way to be deprecated.

When KWallet added Secret Service support, and was later refactored to use Secret Service as its primary backend, those legacy Map entries were converted to JSON, and incorrectly assigned type="map". It would've been more correct to set them to type="plaintext". But what's done is done.

New code will just use QtKeyChain's Text type interface with JSON values, which will be saved correctly as type="plaintext" (e.g. here). But users may still have those old type="map" entries left over, which is why your search fallback fix is needed.

Comment thread qtkeychain/libsecret.cpp
Comment on lines +103 to +107
arg->self->mode = QKeychain::JobPrivate::Text;
secret_password_lookup_fn(qtkeychainSchema(), nullptr, on_password_lookup, arg,
"user", arg->user.toUtf8().constData(), "server",
arg->server.toUtf8().constData(), "type", "map",
nullptr);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check that this correctly returns the map data as JSON via textData(). Since the data is coming from DBus, you might need to internally assign arg->self->mode = QKeychain::JobPrivate::Map, and then do some extra data juggling like in #294.

You can force the backend to KWallet using the QTKEYCHAIN_BACKEND environment variable, and compare the output to the libsecret backend with your changes. Both outputs should be identical.

@michaelk83

Copy link
Copy Markdown

Pinging @notmart to take a look at this also.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants