Skip to content

v0.23.21

Choose a tag to compare

@github-actions github-actions released this 23 Oct 18:53
· 143 commits to main since this release

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>/cmdline while bw ran. BitwardenBackend::store now writes the encoded item to bw'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_cache ran two availability probes (up to 5 s each) with block_on on the GTK main thread, about 7 s with bw and 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 from detect_secret_backends on a background thread. (rustconn/src/state/mod.rs, rustconn/src/app.rs)
  • Bitwarden "Search from vault root" makes one bw call fewer per lookup (issue #353) — with root search on, the scoped RustConn: <id> search ran first although the search by the connection id that follows always returns a superset of it, so a lookup cost four bw list items calls (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_available also trusts a held session instead of running bw --version and bw status. (rustconn-core/src/secret/bitwarden.rs)
  • Settings → Secrets no longer unlocks the Bitwarden vault again when a session exists (issue #353) — bw status on CLI 2026.4+ always reports locked, so opening Settings or switching the backend to Bitwarden ran a new bw unlock every time, outside the unlock lock, which produced the parallel unlocks in the #353 logs. check_bitwarden_status_sync now reports Unlocked at once when RustConn holds a session, and the blocking and async unlock paths share one BW_UNLOCK lock, so a manual Unlock waits for a startup or connect unlock instead of racing it. A held session that was locked outside RustConn (bw lock in 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 through resolve_credentials_gtk now 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 the tty.* dial-in nodes, which block on carrier detect) and ranks the results ttyUSB, ttyACM, cu.usb*, other cu.*, then the built-in ttyS UARTs, numbered nodes in numeric order (ttyUSB2 before ttyUSB10). Before, the list was sorted alphabetically, so the built-in ttyS* ports came ahead of a USB adapter and ttyUSB10 ahead of ttyUSB2. (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 lookup was trimmed, so a password that starts or ends with a space was imported wrong. Only the one trailing newline secret-tool adds is removed now, and the value is held as SecretString with 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_path cleared key_path but left an SshKeySource::File key source in the exported group, so another device received a path to a key file that only exists on the exporting machine. A File key source is exported as Default (let ssh choose), for SSH and SFTP alike; Agent and Inherit are kept. (rustconn-core/src/sync/group_export.rs)
  • The SSH key passphrase is no longer passed to ssh-add in the environment — SshAgentManager::add_key gave the passphrase to its askpass helper in RUSTCONN_ASKPASS_SECRET, readable through /proc/<pid>/environ while ssh-add ran. It now uses the owner-only (0600) secret file in $XDG_RUNTIME_DIR the SSH tunnels already use; the environment carries only the file's path, and the file is zeroized and removed when ssh-add exits. 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-add asks 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, so ssh-add stops and the dialog reports an incorrect passphrase; ssh-add also 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 sync runs at most every 10 minutes while a Bitwarden session is held (issue #353) — each time the 120 s session check expired, auto_unlock also ran bw 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 in store) resets the timer, and sync_on_next_unlock after 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 u128 comparisons in ctutils::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/picky smartcard and crypto chain. cargo deny check advisories is 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.json regenerated 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 sha256 updated 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 on core24 + gnome-46-2404: Snapcraft 9.2 just added core26 support to the gnome extension, 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.RustConn

Snap

sudo snap install rustconn

Debian/Ubuntu (.deb from this release)

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

Fedora (.rpm from this release)

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

AppImage

chmod +x RustConn-0.23.21-x86_64.AppImage
./RustConn-0.23.21-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

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 SHA256SUMS

Signed 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.)