Skip to content

Conversation

cynhr
Copy link

@cynhr cynhr commented Jul 2, 2025

Allow configuring the exposed Freedesktop Secret Service aliases. This is especially relevant for setting the default alias.
Fixes #8479.

This is split into 4 commits:

  • track databases by their public UUID
  • create the config field used to store the alias mapping
  • apply the configured aliases to the Service / Collections
  • add a settings GUI for this config field

Some notes:

  • I'm storing the alias → UUID mapping in roaming (not local) configuration storage. I have the same databases on multiple systems, and I'd like them to be exposed under the same aliases.
    I'm not storing the databases' file paths (which was suggested in one of the issues). I'd be a bit surprised to have a Secret Service D-Bus request create a new database tab (as opposed to only offering to unlock existing database tabs)? But maybe that's just me … If someone ends up implementing automatic database loading, those file paths should probably go into local (not roaming) storage (maybe as an UUID → path mapping?), as file paths are not necessarily identical on all systems.
  • I'm also storing aliases created dynamically (e.g. through FdoSecrets::Service::setAlias, which is exposed to D-Bus, I believe), which is a change from the current behaviour. As a user, I find it a bit surprising that new collection can be created / aliased via D-Bus, but that seems to be the spec.
  • I've not worked much with Qt before. If there's a simpler/nicer way to create this settings GUI (it feels like there must be), I'd appreciate the feedback :)
    • It's a bit annoying that the user has to click to create the editor, click to open the popup, click to select the item, and then click again to dismiss the editor. Would be nicer, to somehow create a dropdown without a QComboBox?
    • I'm not always sure, whether Qt objects take ownership of (raw) pointers I pass them. From the existing code, I'm assuming they do?
  • By copying the file, one can easily end up with two databases with identical public UUIDs. In this case, all aliases for that UUID will map to the database opened first. Which might confuse the user, it'd look like they just cannot configure any other database to be used.
  • I've kept the // static constexpr still requires definition before c++17 for SettingsAliasesModel::ColumnNames for consistency with the other ColumnNames, even though the code uses C++17 features (std::as_const) and the top-level CMakeLists.txt mandates C++17 by now.
  • Also see the respective commit messages.

I did not use any generative AI myself. I did apply suggestions created by Copilot etc., posted to this PR.

Screenshots

image

Testing strategy

None so far.

Type of change

  • ✅ New feature (change that adds functionality)

@cynhr cynhr force-pushed the feature/fdosecrets-alias branch from 807574f to 8638e57 Compare July 2, 2025 21:47
@droidmonkey droidmonkey added feature: Secret Service pr: new feature Pull request adds a new feature labels Jul 2, 2025
@droidmonkey droidmonkey added this to the v2.8.0 milestone Jul 2, 2025
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds support for configuring Freedesktop Secret Service collection aliases by UUID, including storage, lookup, UI, and application in the service layer.

  • Track open databases by their public UUID for alias lookup
  • Introduce a new QVariantMap config field and persist alias⇄UUID mappings
  • Provide a settings UI and apply configured aliases in the FdoSecrets service

Reviewed Changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/gui/DatabaseTabWidget.{h,cpp} Map tabs by public UUID and expose lookup/update methods
src/fdosecrets/widgets/SettingsWidgetFdoSecrets.{ui,cpp} Add “Collection Aliases” settings view and delegate
src/fdosecrets/widgets/SettingsModels.{h,cpp} Implement SettingsAliasesModel for alias⇄UUID mapping
src/fdosecrets/objects/Service.{h,cpp} Apply configured aliases and handle dynamic aliasing
src/fdosecrets/FdoSecretsSettings.{h,cpp} Persist and signal collection alias changes
src/core/Config.{h,cpp} Register new config key for alias mappings
share/translations/keepassxc_en.ts Add translations for new UI strings
Comments suppressed due to low confidence (1)

src/fdosecrets/widgets/SettingsModels.cpp:250

  • There are no unit tests covering SettingsAliasesModel. Consider adding QTest-based tests for rowCount, data(), setData() and moveAlias() scenarios.
    SettingsAliasesModel::SettingsAliasesModel(const DatabaseTabWidget* dbTabs, QObject* parent)

cynhr pushed a commit to cynhr/keepassxc that referenced this pull request Jul 9, 2025
Remove the collectionAliasesChanged() signal from FdoSecretsSettings
to avoid making it a QObject.  Instead connect to Config::changed and
check which Config key changed.
This does break the abstraction layer that FdoSecretsSettings was
between Service and Config, and requires comparing the key each time any
config value is updated, but averts the QObject overhead for
FdoSecretsSettings.

Suggested-by: Jonathan White <[email protected]>
(keepassxreboot#12252 (comment))
@cynhr cynhr force-pushed the feature/fdosecrets-alias branch 2 times, most recently from 5c1f58f to b16c024 Compare July 9, 2025 15:12
@cynhr
Copy link
Author

cynhr commented Jul 9, 2025

So far, there are only tests for checking, that configured aliases are applied (i.e. exposed to DBus). I'd like to also add test for editing a SettingsAliasesModel and for displaying it in the settings screen, but haven't written those yet.

I did have some problems running the tests locally: testguifdosecrets would just hang (even on develop, not my feature branch). I got my tests to run by simply commenting out all other tests in TestGuiFdoSecrets.cpp.
The CI test runners do not appear to have this problem, so probably something on my end.

@cynhr cynhr force-pushed the feature/fdosecrets-alias branch 3 times, most recently from 7a504c2 to 44b0a41 Compare August 21, 2025 14:27
Timon Reinold added 8 commits August 21, 2025 16:58
Add a map from public UUID to database tab to DatabaseTabWidget, to
allow efficiently accessing Databases by public UUID.  Similar to
Database::s_uuidMap.
This commit does not add any user-facing features.

While independently created UUIDs usually don't collide, the public UUID
could be manipulated, or simply duplicated by copying the file.  This
will simply ignore all databases opened while another database with the
same public UUID is already open (even if that first database is later
closed, until the second database is re-opened).
Add a setting to store the Freedesktop Secret Service aliases.
Setting e.g. the "default" alias indicates, to which database most
applications should store new secrets.

This is a QVariantMap (aka QMap<QString, QVariant>) as opposed to a
QMap<QString, QUuid>, as only the former can be stored to QSettings.
Converting a QVariantMap to QMap<QString, QUuid> would require copying
the entire map, calling QVariant::toUuid on every value.

This commit does not yet add the user interface for configuring this
setting, nor does it  apply the configured aliases to the actual D-Bus
service.
Create and remove Freedesktop Secret Service aliases as configured in
FdoSecretSettings, and store aliases created/removed via D-Bus to
FdoSecretSettings.

If the "default" alias has not been configured, this works exactly like
it did before.  If the "default" alias has been configured, but the
corresponding database isn't currently opened (not even
opened-but-locked), no "default" alias is exposed.  This prevents
secrets from accidentally being written to another database (imagine a
database being routinely shared with other people, which now suddenly
contains an access token for your private email, just because the file
system containing your private passwords wasn't mounted).

Providing no "default" alias is already what we're doing if no database
tab is opened.

The implementation would have preferred a "database → Set<alias>"
mapping (compare `Service::applyCollectionAliasSettings`), but "alias →
database" is the natural model making invalid states (multiple databases
owning the same alias) unrepresentable, requiring less validation code.
Fixes keepassxreboot#8479

The QComboBox'es created by DatabaseUuidDelegate::createEditor are not
updated when database tabs are created or destroyed.  A new editor seems
to be created each time the user starts editing a field, so this should
not be a problem.
Remove the collectionAliasesChanged() signal from FdoSecretsSettings
to avoid making it a QObject.  Instead connect to Config::changed and
check which Config key changed.
This does break the abstraction layer that FdoSecretsSettings was
between Service and Config, and requires comparing the key each time any
config value is updated, but averts the QObject overhead for
FdoSecretsSettings.

Suggested-by: Jonathan White <[email protected]>
(keepassxreboot#12252 (comment))
This operator+ is deprecated since Qt6.2:
https://doc.qt.io/archives/qt-6.2/qmap-iterator.html.

QMap is implemented as a red/black tree, presumably without storing
subtree sizes, so this is a linear lookup.  We need to call this for
each displayed alias (multiple times), so linear complexity for lookup
by rank is a bummer.  But presumably nobody's going to have that many
aliases, that this actually matters.

Suggested-by: Copilot
Formulate a single case switch-statement as an if-statement.  If we ever
want to add additional cases, just turn it back into a switch-statement.

Avoid calling QComboBox::setItemData with out-of-bounds indices.  While
QComboBox::insertItem documents that it works with larger indices,
QComboBox::setItemData does not.  So instead use the actual real index
for both.
(Note that QComboBox::addItem also just calls "insertItem(count(),
...)", so QComboBox::addItem wouldn't be any more efficient, but this
way we see both calls actually using the same index.)

Suggested by CodeQL (switch -> if) and Copilot (QComboBox indices).
Verify that configured Freedesktop Secret Service aliases are exposed on
the DBus interface.

Also run some tests against SettingsAliasesModel, using Qt's
QAbstractItemModelTester, which tries to find violations of
QAbstractItemModel's invariants.  Including that we apparently shouldn't
return flags for invalid indices, so check the index's validity in
SettingsAliasesModel::flags().
@cynhr cynhr force-pushed the feature/fdosecrets-alias branch from 44b0a41 to a5531a0 Compare August 21, 2025 15:00
@cynhr cynhr marked this pull request as ready for review August 21, 2025 15:59
@cynhr
Copy link
Author

cynhr commented Aug 22, 2025

This should be ready for review now.

The MacOS failure (at a glance) looks unrelated (something in TestGui::testCreateDatabase() appears to break TestGui::init()'s editPassword->setFocus() for all following tests; and it's also happening in other PR's CI). Or should I have another look at that (don't have a Mac to debug, though)?

@droidmonkey
Copy link
Member

I need to reset macos, don't worry

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

Labels

feature: Secret Service pr: new feature Pull request adds a new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Secret Service: UI to manage alias mappings

2 participants