v0.19.19
What's Changed
Fixed
-
Deleting a connection now removes its credential from the password vault (issue #263) — the reporter confirmed 0.19.18 fixed the rename half of this issue but found that deleting a connection left the entry behind in both KeePassXC and the system keyring. Two independent causes. First, deletion is a soft delete into a trash that acts as the undo buffer, and credential cleanup lived in
AppState::empty_trash— which nothing in the GUI ever called, so no deletion was ever finalized and no credential was ever removed. The Undo toast now defines the undo window: when it dismisses without Undo having been used, the newwin.purge-deletedaction permanently removes that one trash entry and deletes its vault credential on a background thread. Pressing Undo restores the connection with its password intact, tracked by an explicit flag from the toast'sbutton-clickedrather than inferred from trash state, so the purge can never race ahead of the restore. Bulk delete offers no Undo affordance and therefore purges immediately. Second, cleanup used the wrong lookup key for the system keyring:delete_vault_credentialbuilt the flat"{name} ({protocol})"key while 0.19.18 had moved storage to the group-scoped"RustConn/{group}/{name} ({protocol})", and an attribute search that matches nothing reports success — so the delete silently did nothing even when it did run. Cleanup now covers every key format a credential may have been written under, current and legacy. -
Renaming a connection in the configuration panel now updates the vault entry (issue #263) — 0.19.18 fixed the inline rename dialog but not the full connection editor, which is a separate save path. That handler never captured the pre-edit connection and never called any vault migration, so editing the Name field and saving left the credential under the old key. It is the more capable path of the two: it rebuilds the whole connection from the widgets, so one save can change the name, the group and the protocol, and all three are part of the lookup key — something neither existing helper could express, since both took a single protocol string and used it for the old and the new key alike. Key derivation for every rename entry point is now computed by one function that takes the old and new connection and derives each protocol from its own connection;
rename_vault_credentialandrename_vault_credential_for_movebecame thin wrappers over it, so a future gap cannot be fixed in one path and missed in the others. When the user also types a new password, that is written under the new key as before and the now-stale entry under the previous key is removed. -
Credentials of connections outside any group were missed by vault cleanup and migration — found while testing the above.
save_password_to_vaultstores an ungrouped connection underRustConn/{name} ({protocol}), but the new key derivation resolved an absent group to "no group path at all" rather than "an empty group path", producing the bare legacy{name} ({protocol}). Delete and migration therefore looked in the wrong place for every ungrouped connection. All three paths now agree with the resolver. -
System Keyring entries are now visible in KDE Wallet (issue #264) — 0.19.18 added the group path to the keyring key but left the item label as
RustConn: oracle/admin (ssh). kwalletd cannot map a:onto its folder hierarchy and omits such items from its list entirely, so RustConn credentials only ever showed up in GNOME's Seahorse. The label is now a pure/-separated path,RustConn/oracle/admin (ssh), which KDE Wallet renders as nested folders and GNOME Keyring accepts unchanged. The label is cosmetic — lookups match on the item's attribute map, never on the label — so nothing is orphaned; items written by an older release keep their old label until their credential is next saved. -
Moving a connection between groups no longer orphans its keyring entry (issue #264) —
rename_vault_credential_for_moveandmigrate_vault_entries_on_group_changereturned early for every non-KeePass backend, on the assumption that only KeePass embeds the group path in its key. That stopped being true in 0.19.18 for libsecret and the macOS Keychain, so moving a connection to another group, or renaming a group, left the credential under the old path where the resolver no longer looks. Both migrations now handle the keyring backends as well, moving each entry by retrieve → store under the new key → delete the old one, sinceSecretBackendhas no rename operation. Group credentials are keyed by group UUID and are correctly left alone. -
Deleting a group with a vault password no longer leaves a mangled orphan entry in KeePass —
delete_group_vault_credentialoverwrote the entry with an empty username and password instead of deleting it, and passed an already-prefixed path tosave_password_to_kdbx, which prependsRustConn/itself — writing toRustConn/RustConn/Groups/{name}. The entry is now removed withdelete_entry_from_kdbxusing the correct path. -
macOS Keychain credentials were stored where the resolver never looked —
generate_store_key_with_groupspecial-cased onlyLibSecret, so the Keychain fell through to the flatrustconn/{name}key whileCredentialResolverresolved it through the hierarchical keyring path (RustConn/{group}/{name} ({protocol})), the same as libsecret. Saving a vault password on macOS therefore produced an entry that could not be read back. The store key now matches the resolver, and the old flat key is included in fallback and cleanup lookups so existing entries are still found.
Improved
-
Keyring credential retrieval wipes its intermediate plaintext buffers —
LibSecretBackend::retrieve_valuedecoded the secret through aStringthat was left un-wiped on drop, and the malformed-UTF-8 error path dropped a buffer still holding the raw bytes; the error message also embedded theFromUtf8Error. Both now matchkeyring::lookup: the byte buffer isZeroizing, the error buffer is wiped explicitly, and the message is a static string.retrievealso fetches the non-secret fields first and wraps each secret inSecretStringas it is read, so no plainStringholding secret material stays alive across a later fallible await. -
One implementation for every vault key migration — the rename, group-move and group-rename paths each carried their own copy of the key-derivation logic, which is how the group path reached the keys in 0.19.18 without reaching three of the four migrations. Key derivation now lives in a single function that takes the old and new connection;
rename_vault_credentialandrename_vault_credential_for_moveare thin wrappers over it. Derivation is separated from the vault I/O so it is unit-testable without a live backend, and is covered by tests for a rename, a group change, a protocol change, all three at once, the KeePass variant and the flat-key backends.
Changed
-
The saved interface language is now applied only during startup, before any thread exists — RUSTSEC-2026-0244 reports
gettext-rssetlocaleas unsound when called from a multi-threaded program. RustConn called it from three places, and one of them —apply_language()from the GTKactivatehandler — ran after the GIO worker thread was already up. That call site is removed.apply_language_from_config()now applies the locale on every path it takes, frommain(), before the tracing subscriber, GTK and tokio exist, which is the single-threaded precondition the advisory itself names as safe. Behaviour is preserved, including the Flatpak case the removed call existed for:LANGUAGEalone is not enough, because gettext ignores it whenLC_MESSAGESresolves to"C"— which is what happens in a sandbox whose host locale is not installed (issue #158). Changing the language in Settings still takes effect on the next start, as before; the removed call could not retranslate already-rendered GTK labels either.The fixed
gettext-rs0.8.0 is deliberately not adopted: its fix is to marksetlocaleunsafe, and this crate forbidsunsafe_code, with a workspace guard confining unsafe torustconn-*-syscrates. The advisory is instead recorded indeny.tomland.cargo/audit.tomltogether with the call-site analysis above; the upgrade path is to move the call into a dedicatedrustconn-locale-syscrate.
Dependencies
- Updated: openh264 + openh264-sys2 0.9.7→0.9.8, zbus + zbus_macros 5.18.0→5.19.0, zvariant + zvariant_derive 5.13.1→5.14.0, zvariant_utils 3.5.0→4.0.0 (pulls in syn 3.0.3 and zcheapstr 1.0.0 transitively).
Installation
Flatpak (Recommended)
flatpak install flathub io.github.totoshko88.RustConnSnap
sudo snap install rustconnDebian/Ubuntu (.deb from this release)
sudo dpkg -i rustconn_0.19.19_amd64.deb
sudo apt-get install -f # Install dependencies if neededFedora (.rpm from this release)
sudo dnf install rustconn-0.19.19-1.fc44.x86_64.rpmAppImage
chmod +x RustConn-0.19.19-x86_64.AppImage
./RustConn-0.19.19-x86_64.AppImagemacOS (Homebrew)
brew tap totoshko88/rustconn
brew install rustconn
open $(brew --prefix)/opt/rustconn/RustConn.appAll dependencies (GTK4, libadwaita, VTE, Adwaita icons) are installed automatically.
Requires macOS 13 (Ventura) or later.
OBS Repositories
Packages available at: https://build.opensuse.org/package/show/home:totoshko88:rustconn/rustconn
# Debian 13 (Trixie)
echo 'deb http://download.opensuse.org/repositories/home:/totoshko88:/rustconn/Debian_13/ /' \
| sudo tee /etc/apt/sources.list.d/rustconn.list
curl -fsSL https://download.opensuse.org/repositories/home:/totoshko88:/rustconn/Debian_13/Release.key \
| gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/rustconn.gpg > /dev/null
sudo apt update && sudo apt install rustconn
# Ubuntu 24.04 LTS (Noble)
echo 'deb http://download.opensuse.org/repositories/home:/totoshko88:/rustconn/xUbuntu_24.04/ /' \
| sudo tee /etc/apt/sources.list.d/rustconn.list
curl -fsSL https://download.opensuse.org/repositories/home:/totoshko88:/rustconn/xUbuntu_24.04/Release.key \
| gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/rustconn.gpg > /dev/null
sudo apt update && sudo apt install rustconn
# Ubuntu 26.04 LTS (Resolute)
echo 'deb http://download.opensuse.org/repositories/home:/totoshko88:/rustconn/xUbuntu_26.04/ /' \
| sudo tee /etc/apt/sources.list.d/rustconn.list
curl -fsSL https://download.opensuse.org/repositories/home:/totoshko88:/rustconn/xUbuntu_26.04/Release.key \
| gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/rustconn.gpg > /dev/null
sudo apt update && sudo apt install rustconn
# Fedora 44
sudo dnf config-manager addrepo --from-repofile=https://download.opensuse.org/repositories/home:/totoshko88:/rustconn/Fedora_44/home:totoshko88:rustconn.repo
sudo dnf install rustconn
# Fedora 43
sudo dnf config-manager addrepo --from-repofile=https://download.opensuse.org/repositories/home:/totoshko88:/rustconn/Fedora_43/home:totoshko88:rustconn.repo
sudo dnf install rustconn
# openSUSE Tumbleweed
sudo zypper ar https://download.opensuse.org/repositories/home:/totoshko88:/rustconn/openSUSE_Tumbleweed/ rustconn
sudo zypper ref && sudo zypper in rustconn
# openSUSE Leap 16.0
sudo zypper ar https://download.opensuse.org/repositories/home:/totoshko88:/rustconn/openSUSE_Leap_16.0/ rustconn
sudo zypper ref && sudo zypper in rustconnArch Linux (AUR)
yay -S rustconnFreeBSD (Ports)
pkg install rustconnFull installation guide: https://github.com/totoshko88/RustConn/blob/main/docs/INSTALL.md