Skip to content

v0.23.18

Choose a tag to compare

@github-actions github-actions released this 20 Oct 23:33
· 30 commits to main since this release

What's Changed

Improved

  • rustconn-cli secret get/set/delete build one Tokio runtime per command, not one per backend branch — each backend arm created its own tokio::runtime::Runtime::new() before its single block_on, so a command spun up (and tore down) a fresh multi-thread runtime for one call. The three commands now share one lazily-created current-thread runtime through a secret_runtime() helper (22 call sites), which is all a one-shot CLI needs. Behaviour is unchanged. (rustconn-cli/src/commands/secret.rs)
  • Tag filtering no longer allocates a String per tag — ConnectionManager::filter_by_tag and filter_by_tags lower-cased both the query and every connection's every tag into fresh Strings on each call (filter_by_tags even rebuilt a Vec<String> of lower-cased tags per connection). They now compare through an allocation-free, Unicode-aware eq_ignore_case helper that folds case lazily, so filtering the sidebar allocates nothing per tag. Matching stays case-insensitive with the same Unicode semantics as the old to_lowercase (so Ä still matches ä), unlike an ASCII-only comparison. (rustconn-core/src/connection/manager.rs)
  • CSV export no longer duplicates its field mapper and resolves group paths in linear time — the bulk export_to_string and the single-connection export_connection carried two near-identical match field { … } blocks that could drift apart, and the bulk path re-scanned the whole group slice for every connection to build each group path (O(connections × groups)). The per-field mapping is now one shared field_value helper, and the group lookup goes through a HashMap built once per export so each hierarchy hop is O(1). Output is byte-for-byte unchanged; a regression is guarded by the existing round-trip tests. (rustconn-core/src/export/csv_export.rs)
  • M-PUBLIC-DEBUG guard tests for five more password-bearing types — SshTunnelParams, VncClientConfig, VerifiedCredentials, KdbxEntry and CredentialUpdate each derive Debug while holding a pub password: Option<SecretString> but had no test proving the derived output does not leak the plaintext. secrecy redacts itself today, so there is no leak now, but a future field or a switch to a manual Debug could silently start leaking; these tests make that a compile-and-test guarantee, matching the guards RdpClientConfig/SpiceClientConfig and the secret backends already carry. (rustconn-core/src/ssh_tunnel.rs, rustconn-core/src/secret/kdbx.rs, rustconn-core/src/secret/verification.rs, rustconn-core/src/secret/manager.rs, rustconn-core/tests/properties/vnc_client_tests.rs)

Documentation

  • CLI reference: delete in non-interactive mode now documents the real behaviour — the reference said that with piped stdin "confirmation is automatically assumed", implying the connection is deleted. The code does the opposite: connection delete without --force and with no terminal aborts and deletes nothing, the safe default scripts rely on. A script trusting the old wording would silently fail to delete. The line now states that it aborts without --force and that --force is required to delete unattended. (docs/CLI_REFERENCE.md)

Fixed

  • Ásbrú export never writes a dead entry for an unsupported protocol, whichever entry point is used — the ExportTarget wrapper skips SPICE, Serial, Kubernetes, Mosh and Web (no round-trippable Ásbrú method:), but the raw AsbruExporter::export builder and the public connection_to_entry sat below that guard and would still emit a method: "SPICE" entry that neither Ásbrú-CM nor RustConn's own importer can read back. The raw builder now skips the same unsupported protocols itself, so a direct call (or a future caller) cannot bypass the guard. The protocol list is now a single protocol_round_trips source of truth that supports_protocol delegates to, and the stale comment claiming those protocols "don't have additional fields" is corrected. (rustconn-core/src/export/asbru.rs)
  • SSH jump-host passwords no longer travel in the process environment — three single-hop SSH paths (the embedded RDP/VNC/SPICE/Telnet jump-host tunnel in ssh_tunnel, the standalone Tunnel Manager, and the background monitoring SSH client) gave the password to their SSH_ASKPASS helper through an environment variable (_RC_TUN_PW/_RC_MON_PW). A process environment is readable by the same user through /proc/<pid>/environ for the life of the process, a weaker channel than the file-path indirection the multi-hop path (issue #203) already uses. All three now write the password to an owner-only (mode 0600) file in $XDG_RUNTIME_DIR and pass only that file's path in the environment; the helper script reads the file, and the password value never enters the SSH process environment. The files are zeroized and removed when the tunnel or monitoring session ends. The Tunnel Manager's helper also moves off world-readable /tmp onto the same runtime-dir resolver, and the three duplicate askpass implementations collapse into one shared pair of helpers in ssh_tunnel. (rustconn-core/src/ssh_tunnel.rs, rustconn-core/src/tunnel_manager.rs, rustconn-core/src/monitoring/ssh_exec.rs)
  • Custom/extra RDP, VNC, Telnet, Serial and Zero Trust arguments now survive quotes and spaces — the connection editor and the template dialog split every custom-args field with a bare split_whitespace(), so a quoted argument or a value containing a space (a FreeRDP drive mapping such as /drive:docs,"/home/u/My Docs", or any flag whose value has a space) was silently torn into separate argv tokens and reached the client malformed. All six sites now route through the shared, quote-aware rustconn_core::dialog_utils::parse_args (built on shell_words::split, already used elsewhere), which keeps a quoted value as one argument and falls back to a plain whitespace split only on an unbalanced quote. Removing the five duplicate parsers also leaves one place to change this behaviour. (rustconn-core/src/dialog_utils.rs, rustconn/src/dialogs/connection/builders.rs, rustconn/src/dialogs/template.rs)
  • Ásbrú import now holds passwords as SecretString, not plain String — the AsbruEntry.pass/password fields and the public AsbruImporter::extract_password returned a bare String, so a password read from an Ásbrú YAML file lingered in a plain heap allocation that was neither redacted in Debug nor zeroised on drop, diverging from the RDM importer (rdm.rs), which already wraps the same field in SecretString per secrets-guide.md rule #6. Both fields and the extractor return value are now Option<secrecy::SecretString>; secrecy deserialises straight from the YAML, so the plaintext never materialises as a long-lived String. Password import stays off by default and still only marks the connection PasswordSource::Prompt. (rustconn-core/src/import/asbru.rs)

Added

  • RDP Color Depth can now be set to "Negotiate (server default)", which stops RustConn from sending /bpp: to FreeRDP (issue #381) — the colour-depth dropdown in the connection editor and the template dialog always resolved to an explicit value (index 0 was 32-bit), so every GUI-configured RDP connection stored color_depth = Some(..) and the external/embedded FreeRDP launcher always emitted /bpp:. Some servers answer an explicit /bpp: by tearing the session down — KRdp replies to /bpp:32 with PDU_TYPE_DEACTIVATE_ALL (already worked around internally for #366), and the hosts in #381 connect from wlfreerdp3/sdl-freerdp3 only when /bpp is omitted. A new first dropdown entry, Negotiate (server default), stores color_depth = None, so no /bpp: reaches FreeRDP and it negotiates the depth with the server — matching what a bare xfreerdp /v:… does. The save and load mappings in both dialogs shift accordingly (None→index 0, 32→1, 24→2, 16→3, 15→4, 8→5), and because a new connection's model default is already None, new connections now default to Negotiate. The native IronRDP path is unaffected (it still drives its own 32-bit framebuffer for AWS EC2 compatibility). (rustconn/src/dialogs/connection/rdp.rs, rustconn/src/dialogs/connection/builders.rs, rustconn/src/dialogs/connection/dialog/populate.rs, rustconn/src/dialogs/template.rs)

Dependencies

  • Updated: ksni 0.3.6 → 0.3.7 (system-tray backend; pulls in arc-swap 1.9.3 and crossbeam-queue 0.3.14 transitively). Semver-compatible; cargo-sources.json regenerated for the Flatpak/Flathub manifests. No security advisories affected.
  • Documented five accepted unmaintained transitive advisories in deny.toml — cargo audit reports unsafe-libyaml (via serde_yaml_ng), zbus_names/zvariant/zvariant_derive (via the zbus 5.19 desktop-integration stack — ashpd/ksni/oo7) and atomic-polyfill (deep under the ironrdp→sspi smartcard chain through heapless 0.7) as unmaintained. None is a vulnerability and each is pinned by an upstream RustConn does not control, so the fix is an upstream release in every case. cargo-deny already passes (unmaintained = "workspace" fails only on workspace-direct crates, so none is in ignore); the provenance and upgrade path of each are now recorded in deny.toml so a future audit recognises them as tracked rather than new. (deny.toml)

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.18_amd64.deb
sudo apt-get install -f  # Install dependencies if needed

Fedora (.rpm from this release)

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

AppImage

chmod +x RustConn-0.23.18-x86_64.AppImage
./RustConn-0.23.18-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.18-x86_64.AppImage --repo totoshko88/RustConn

(The snap is signed by the Snap Store; the macOS build is delivered via the Homebrew tap.)