Repository navigation
v0.23.21
What's Changed
Fixed
- Embedded RDP "Save N Files" no longer times out without saving after the folder dialog closes (issue #390) — when the folder picker was a portal window (Flatpak, Snap), returning focus to RustConn made GTK report a clipboard change, and the local-clipboard monitor announced text to the server. That announcement replaces the server's clipboard, so the files being fetched were no longer offered: the request went unanswered, IronRDP gave up after 60 s and the button went back to "Save N Files" with nothing written. The monitor now holds local announcements from the moment Save is pressed until the batch settles, and a change seen meanwhile is announced once afterwards; a cancelled or failed folder dialog is now logged and releases the hold. (
rustconn/src/embedded_rdp/thread.rs,rustconn/src/embedded_rdp/polling_handlers.rs,rustconn/src/embedded_rdp/mod.rs,rustconn/src/embedded_rdp/connection.rs) - Bitwarden: item contents are passed to bw via stdin instead of command-line arguments — saving a credential ran
bw create item <base64>/bw edit item <id> <base64>, and that base64 item holds the plaintext password, so any local user could read it from/proc/<pid>/cmdlinewhilebwran.BitwardenBackend::storenow writes the encoded item tobw's stdin (the CLI reads it there when the argument is absent), on the create, edit and "out of date" retry paths alike; the buffer is still wiped on drop. (rustconn-core/src/secret/bitwarden.rs) - No more UI freeze after the startup Bitwarden unlock and after every Settings save (issue #353) —
AppState::refresh_secret_backend_cacheran two availability probes (up to 5 s each) withblock_onon the GTK main thread, about 7 s withbwand a stall for every CLI backend, to fill a cache nothing read. The dead cache and its four call sites are removed; the startup banner and the sidebar status already come fromdetect_secret_backendson a background thread. (rustconn/src/state/mod.rs,rustconn/src/app.rs) - Bitwarden "Search from vault root" makes one
bwcall fewer per lookup (issue #353) — with root search on, the scopedRustConn: <id>search ran first although the search by the connection id that follows always returns a superset of it, so a lookup cost fourbw list itemscalls (4–4.5 s each in the reporter's log). The scoped search is now skipped, giving three calls with the same match rules: RustConn's own item still wins over a bare title match.BitwardenBackend::is_availablealso trusts a held session instead of runningbw --versionandbw status. (rustconn-core/src/secret/bitwarden.rs) - Settings → Secrets no longer unlocks the Bitwarden vault again when a session exists (issue #353) —
bw statuson CLI 2026.4+ always reportslocked, so opening Settings or switching the backend to Bitwarden ran a newbw unlockevery time, outside the unlock lock, which produced the parallel unlocks in the #353 logs.check_bitwarden_status_syncnow reports Unlocked at once when RustConn holds a session, and the blocking and async unlock paths share oneBW_UNLOCKlock, so a manual Unlock waits for a startup or connect unlock instead of racing it. A held session that was locked outside RustConn (bw lockin a terminal) is no longer replaced silently on the next Settings open; press Unlock there or restart RustConn. (rustconn/src/dialogs/settings/secrets_tab/detection.rs,rustconn-core/src/secret/bitwarden.rs) - Repeated credential fetches are served from the session cache (issue #353) — Copy Username, Copy Password and the editor's Load password from vault asked the vault every time, and only a Connect filled the cache, so fetching the same credentials twice in a row ran the full vault lookup (several seconds with
bw) twice. Every vault read throughresolve_credentials_gtknow caches the answer; the editor's Load uses the cache only while the editor's lookup fields match the saved Vault connection. A password-only answer is not cached for RDP and Web, which need a user name, and a failed connection still drops the entry (issue #351). Editing or deleting a connection drops its entry too, so a password changed in the editor is not replayed from the cache, and expired entries are removed from memory instead of only being skipped. (rustconn/src/state/mod.rs,rustconn/src/state/connections.rs,rustconn/src/window/copy_field_actions.rs,rustconn/src/dialogs/connection/dialog/passwords.rs) - Serial Auto-Detect finds macOS ports and offers USB adapters first — the scan only knew Linux node names, so on macOS it found nothing. It now offers
/dev/cu.*call-out devices (not thetty.*dial-in nodes, which block on carrier detect) and ranks the resultsttyUSB,ttyACM,cu.usb*, othercu.*, then the built-inttySUARTs, numbered nodes in numeric order (ttyUSB2beforettyUSB10). Before, the list was sorted alphabetically, so the built-inttyS*ports came ahead of a USB adapter andttyUSB10ahead ofttyUSB2. (rustconn/src/dialogs/connection/serial.rs) - Remmina import keeps leading and trailing spaces in passwords — the password read back from the keyring with
secret-tool lookupwas trimmed, so a password that starts or ends with a space was imported wrong. Only the one trailing newlinesecret-tooladds is removed now, and the value is held asSecretStringwith its buffers wiped. Each lookup also has a 30 s limit, so a keyring unlock prompt left open no longer holds the import indefinitely; past it the connection is imported without its password. (rustconn-core/src/import/remmina.rs) - Group Sync no longer spreads a local SSH key file path —
strip_ssh_key_pathclearedkey_pathbut left anSshKeySource::Filekey source in the exported group, so another device received a path to a key file that only exists on the exporting machine. AFilekey source is exported asDefault(let ssh choose), for SSH and SFTP alike;AgentandInheritare kept. (rustconn-core/src/sync/group_export.rs) - The SSH key passphrase is no longer passed to
ssh-addin the environment —SshAgentManager::add_keygave the passphrase to its askpass helper inRUSTCONN_ASKPASS_SECRET, readable through/proc/<pid>/environwhilessh-addran. It now uses the owner-only (0600) secret file in$XDG_RUNTIME_DIRthe SSH tunnels already use; the environment carries only the file's path, and the file is zeroized and removed whenssh-addexits. macOS has no runtime dir, so there the file sits in the per-user$TMPDIR, as the tunnel's already does. (rustconn-core/src/ssh_agent/mod.rs,rustconn-core/src/ssh_tunnel.rs) - A wrong SSH key passphrase no longer freezes RustConn — after a wrong passphrase
ssh-addasks again until its askpass helper gives an empty answer, and the helper repeated the same passphrase forever, so adding a key from Settings → SSH Agent hung the window. The helper now answers once and empties its file after the read, sossh-addstops and the dialog reports an incorrect passphrase;ssh-addalso runs under a 30 s limit after which it is killed and the passphrase file is still removed. (rustconn-core/src/ssh_agent/mod.rs,rustconn-core/src/ssh_tunnel.rs)
Changed
bw syncruns at most every 10 minutes while a Bitwarden session is held (issue #353) — each time the 120 s session check expired,auto_unlockalso ranbw sync, a few seconds per connect. A separate 10-minute sync TTL now gates that step. A fresh unlock still syncs every time, a successful sync from any path (including the "out of date" retry instore) resets the timer, andsync_on_next_unlockafter a rejected password still forces a sync (issue #351). The 10 minutes are wall-clock time, so a suspend counts towards them. (rustconn-core/src/secret/bitwarden.rs)
Dependencies
- ctutils 0.4.3 → 0.4.5 (RUSTSEC-2026-0385) — fixes non-constant-time mask generation and
u128comparisons inctutils::Choice, which could branch on a secret value on common platforms and leak it through a covert timing channel; pulled in transitively under the IronRDP/sspi/rsa/pickysmartcard and crypto chain.cargo deny check advisoriesis clean again. - Updated (semver-compatible): cc 1.9.0 → 1.10.0, crypto-bigint 0.7.5 → 0.7.6, smallvec 1.16.3 → 1.16.4, uuid 1.28.0 → 1.29.0;
cargo-sources.jsonregenerated for the Flatpak/Flathub manifests. - Flatpak — OpenH264 2.6.0 → 2.7.0 — the bundled embedded-RDP H.264 decoder/encoder picks up a batch of hardening fixes (several out-of-bounds, use-after-free and integer-overflow guards in the decoder's threaded and rate-control paths); version and
sha256updated in both the local and Flathub manifests. GNOME runtime 51, FreeRDP 3.32.2, cJSON 1.7.19 and the bundled VTE 0.84.1 were already current; every downloadable CLI tool resolves current (TigerVNC pinned 1.16.2). The Snap stays oncore24+gnome-46-2404: Snapcraft 9.2 just added core26 support to thegnomeextension, but moving the base is a multi-step migration (libadwaita 1.8 features, re-checked staged package names, a full strict-confinement smoke test) that needs its own change rather than a version bump here — tracked as a proposal for 0.24 (issue #174).
Installation
Flatpak (Recommended)
flatpak install flathub io.github.totoshko88.RustConnSnap
sudo snap install rustconnDebian/Ubuntu (.deb from this release)
sudo dpkg -i rustconn_0.23.21_amd64.deb
sudo apt-get install -f # Install dependencies if neededFedora (.rpm from this release)
sudo dnf install rustconn-0.23.21-1.fc44.x86_64.rpmAppImage
chmod +x RustConn-0.23.21-x86_64.AppImage
./RustConn-0.23.21-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
Verifying your download
Every binary on this release (deb, rpm, AppImage, Flatpak) is covered two ways.
Plain checksums — download SHA256SUMS alongside the asset, then:
sha256sum -c SHA256SUMSSigned build provenance (SLSA, via Sigstore) — proves the file was built by this
workflow from this commit:
gh attestation verify RustConn-0.23.21-x86_64.AppImage --repo totoshko88/RustConn(The snap is signed by the Snap Store; the macOS build is delivered via the Homebrew tap.)