Skip to content

v0.19.19

Choose a tag to compare

@github-actions github-actions released this 09 Aug 20:15
· 13 commits to main since this release

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 new win.purge-deleted action 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's button-clicked rather 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_credential built 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_credential and rename_vault_credential_for_move became 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_vault stores an ungrouped connection under RustConn/{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_move and migrate_vault_entries_on_group_change returned 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, since SecretBackend has 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 KeePassdelete_group_vault_credential overwrote the entry with an empty username and password instead of deleting it, and passed an already-prefixed path to save_password_to_kdbx, which prepends RustConn/ itself — writing to RustConn/RustConn/Groups/{name}. The entry is now removed with delete_entry_from_kdbx using the correct path.

  • macOS Keychain credentials were stored where the resolver never lookedgenerate_store_key_with_group special-cased only LibSecret, so the Keychain fell through to the flat rustconn/{name} key while CredentialResolver resolved 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 buffersLibSecretBackend::retrieve_value decoded the secret through a String that 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 the FromUtf8Error. Both now match keyring::lookup: the byte buffer is Zeroizing, the error buffer is wiped explicitly, and the message is a static string. retrieve also fetches the non-secret fields first and wraps each secret in SecretString as it is read, so no plain String holding 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_credential and rename_vault_credential_for_move are 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-rs setlocale as unsound when called from a multi-threaded program. RustConn called it from three places, and one of them — apply_language() from the GTK activate handler — 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, from main(), 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: LANGUAGE alone is not enough, because gettext ignores it when LC_MESSAGES resolves 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-rs 0.8.0 is deliberately not adopted: its fix is to mark setlocale unsafe, and this crate forbids unsafe_code, with a workspace guard confining unsafe to rustconn-*-sys crates. The advisory is instead recorded in deny.toml and .cargo/audit.toml together with the call-site analysis above; the upgrade path is to move the call into a dedicated rustconn-locale-sys crate.

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.RustConn

Snap

sudo snap install rustconn

Debian/Ubuntu (.deb from this release)

sudo dpkg -i rustconn_0.19.19_amd64.deb
sudo apt-get install -f  # Install dependencies if needed

Fedora (.rpm from this release)

sudo dnf install rustconn-0.19.19-1.fc44.x86_64.rpm

AppImage

chmod +x RustConn-0.19.19-x86_64.AppImage
./RustConn-0.19.19-x86_64.AppImage

macOS (Homebrew)

brew tap totoshko88/rustconn
brew install rustconn
open $(brew --prefix)/opt/rustconn/RustConn.app

All 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 rustconn

Arch Linux (AUR)

yay -S rustconn

FreeBSD (Ports)

pkg install rustconn

Full installation guide: https://github.com/totoshko88/RustConn/blob/main/docs/INSTALL.md