Repository navigation
v0.23.18
What's Changed
Improved
rustconn-cli secret get/set/deletebuild one Tokio runtime per command, not one per backend branch — each backend arm created its owntokio::runtime::Runtime::new()before its singleblock_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 asecret_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
Stringper tag —ConnectionManager::filter_by_tagandfilter_by_tagslower-cased both the query and every connection's every tag into freshStrings on each call (filter_by_tagseven rebuilt aVec<String>of lower-cased tags per connection). They now compare through an allocation-free, Unicode-awareeq_ignore_casehelper that folds case lazily, so filtering the sidebar allocates nothing per tag. Matching stays case-insensitive with the same Unicode semantics as the oldto_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_stringand the single-connectionexport_connectioncarried two near-identicalmatch 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 sharedfield_valuehelper, and the group lookup goes through aHashMapbuilt 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,KdbxEntryandCredentialUpdateeach deriveDebugwhile holding apub password: Option<SecretString>but had no test proving the derived output does not leak the plaintext.secrecyredacts itself today, so there is no leak now, but a future field or a switch to a manualDebugcould silently start leaking; these tests make that a compile-and-test guarantee, matching the guardsRdpClientConfig/SpiceClientConfigand 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:
deletein 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 deletewithout--forceand 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--forceand that--forceis 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
ExportTargetwrapper skips SPICE, Serial, Kubernetes, Mosh and Web (no round-trippable Ásbrúmethod:), but the rawAsbruExporter::exportbuilder and the publicconnection_to_entrysat below that guard and would still emit amethod: "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 singleprotocol_round_tripssource of truth thatsupports_protocoldelegates 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 theirSSH_ASKPASShelper through an environment variable (_RC_TUN_PW/_RC_MON_PW). A process environment is readable by the same user through/proc/<pid>/environfor 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_DIRand 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/tmponto the same runtime-dir resolver, and the three duplicate askpass implementations collapse into one shared pair of helpers inssh_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-awarerustconn_core::dialog_utils::parse_args(built onshell_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 plainString— theAsbruEntry.pass/passwordfields and the publicAsbruImporter::extract_passwordreturned a bareString, so a password read from an Ásbrú YAML file lingered in a plain heap allocation that was neither redacted inDebugnor zeroised on drop, diverging from the RDM importer (rdm.rs), which already wraps the same field inSecretStringpersecrets-guide.mdrule #6. Both fields and the extractor return value are nowOption<secrecy::SecretString>;secrecydeserialises straight from the YAML, so the plaintext never materialises as a long-livedString. Password import stays off by default and still only marks the connectionPasswordSource::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 storedcolor_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:32withPDU_TYPE_DEACTIVATE_ALL(already worked around internally for #366), and the hosts in #381 connect fromwlfreerdp3/sdl-freerdp3only when/bppis omitted. A new first dropdown entry, Negotiate (server default), storescolor_depth = None, so no/bpp:reaches FreeRDP and it negotiates the depth with the server — matching what a barexfreerdp /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 alreadyNone, 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.jsonregenerated for the Flatpak/Flathub manifests. No security advisories affected. - Documented five accepted unmaintained transitive advisories in
deny.toml—cargo auditreportsunsafe-libyaml(viaserde_yaml_ng),zbus_names/zvariant/zvariant_derive(via thezbus5.19 desktop-integration stack — ashpd/ksni/oo7) andatomic-polyfill(deep under the ironrdp→sspi smartcard chain throughheapless0.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-denyalready passes (unmaintained = "workspace"fails only on workspace-direct crates, so none is inignore); the provenance and upgrade path of each are now recorded indeny.tomlso a future audit recognises them as tracked rather than new. (deny.toml)
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.18_amd64.deb
sudo apt-get install -f # Install dependencies if neededFedora (.rpm from this release)
sudo dnf install rustconn-0.23.18-1.fc44.x86_64.rpmAppImage
chmod +x RustConn-0.23.18-x86_64.AppImage
./RustConn-0.23.18-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.18-x86_64.AppImage --repo totoshko88/RustConn(The snap is signed by the Snap Store; the macOS build is delivered via the Homebrew tap.)