Skip to content

v0.23.6

Choose a tag to compare

@github-actions github-actions released this 08 Oct 21:42
· 81 commits to main since this release

What's Changed

Added

  • OSC 52: a remote yank can reach the local clipboard (opt-in) — VTE parses OSC 52 ; c ; <base64> and then drops it: through 0.84 its XTERM_SET_XSELECTION handler is a no-op, so a yank in a remote Neovim — or in tmux with set-clipboard external — put the text nowhere. GNOME Terminal and xfce4-terminal inherit the same hole, so this was a missing capability rather than a RustConn bug, and RustConn needs its own because VTE has no API to switch the handler on. A new terminal::osc52::Osc52Filter sits on the session output path (TerminalNotebook::deliver_output_to), lifts the offers out of the PTY stream before Terminal::feed sees them, and writes them through the same display().clipboard().set_text() call copy-on-select uses. It is a byte filter rather than a parser for its own sake: every other byte is passed through in order — OSC 0 titles, OSC 133 shell-integration marks, plain ESC sequences — and a string the stream ends inside is handed back by finish() instead of being kept, because an unterminated OSC left in the stream would make VTE swallow the rest of the session as body. A sequence can straddle PTY reads (8 KiB READ_CHUNK), so the filter keeps state between chunks; one test feeds the same offer at every possible split point and one byte at a time and requires identical output. All three terminators (ESC \, BEL, C1 ST) and both introducers (7-bit and C1) are recognised. Security: the switch is Settings → Terminal → "Remote clipboard (OSC 52)" and defaults to off, since a host that can write the clipboard can aim a pastejacking payload at the next terminal the user pastes into. Reads are never served in any configuration — an OSC 52 ; c ; ? query is dropped unanswered, so the local clipboard cannot be exfiltrated this way — only the c (CLIPBOARD) selection is honoured, with p (primary) and s (select) passed through untouched. A payload is capped at 1 MiB, is base64-decoded into a Zeroizing buffer so the plaintext is wiped on drop, must decode to valid UTF-8 to reach the clipboard, and the decoded text is never logged. The output filter runs before session-transcript observers too, so an enabled offer is lifted out of the saved log as well as the display; with the setting off the sequence reaches both untouched. Remote tmux needs set-clipboard external (and allow-passthrough on) to forward the sequence; a DCS-wrapped passthrough is not unwrapped yet. (PR #372, thanks @shafiev)
  • Save a terminal session's output to a text file — a new Save Output… entry in a terminal tab's right-click menu writes the session's full scrollback to a plain-text file through VTE's write_contents_sync (requested in #371). A file chooser opens with a name derived from the session; the whole buffer is saved (its length is bounded by the Scrollback lines setting). The item is offered only for VTE terminal tabs — SSH, local shell, Telnet, Serial — gated on the session having a terminal widget, so embedded RDP/VNC/Web tabs and the Welcome tab, which have no text buffer, do not show it. In a split tab the focused pane is saved — the window wires a focused-session resolver into the notebook (keyed by the tab owner, mirroring the existing split-pane-box provider) so the save targets the pane the user clicked, not always the first one. A save failure is reported in a modal error dialog and a success in a toast, per the project's error-feedback rule; a cancelled chooser is silent. session_output_filename sanitises the default name (every non-alphanumeric character becomes _, with a terminal-output fallback) and is unit-tested. (#371)

Fixed

  • RDP Performance Mode now reaches the external FreeRDP client — the per-connection Performance Mode (Quality/Balanced/Speed) was applied by the embedded IronRDP client and written into exported .rdp files, but the external FreeRDP launch path dropped it entirely: a Speed profile reached xfreerdp with wallpaper, themes and full-window drag all on, visually identical to Quality (reported on #370). The user's choice was stored but never consumed on that path. FreeRdpConfig now carries performance_mode, threaded from the persisted model through both external launch sites (the direct External client and the embedded→external fallback), and build_freerdp_args emits the matching experience flags — +window-drag +menu-anims for Quality, nothing for Balanced (FreeRDP's own default), -wallpaper -themes for Speed. The mapping mirrors the embedded client's build_performance_flags and the .rdp exporter's write_performance_settings so the three paths cannot drift, pinned by a new freerdp_experience_args_match_mode test. The remote server still has the final say (a group policy such as Enforce Removal of Remote Desktop Wallpaper overrides the client request). The editor's Performance Mode row subtitle now reads "…for image rendering and visual effects" to match the widened reach. (#370)
  • KeePass "Search from vault root" no longer crashes on a vault with non-ASCII entry names — the from-root matcher tested whether a listing line ended with /<candidate> by byte-slicing the line at line.len() - candidate.len() - 1. On a database holding non-ASCII paths — a Cyrillic recycle-bin group (Смітник/…), a database titled Паролі — that index can fall inside a multi-byte UTF-8 character, so the slice panicked and took the whole root search (and the connect) down with it. The same byte-boundary class of bug as the hex-colour crash in #343. The tail test now uses ends_with on the whole string with no byte indexing, so a credential kept outside the RustConn group is found whatever script the surrounding entries are named in. A regression test feeds the matcher a Cyrillic-laden listing. (#353)
  • The misleading "Bitwarden: CLI command path stored" log line no longer reads like a vault lookup — a KeePass user who turned on debug logging to diagnose a credential miss saw this line and reasonably concluded RustConn was querying Bitwarden for their secret (reported while investigating #353). It is nothing of the sort: it is the Settings page's backend-detection caching the resolved bw binary name, and with KeePass selected no Bitwarden backend is ever part of credential resolution. The line now says so explicitly ("cached CLI binary path from backend detection (not a vault lookup)"). (#353)
  • rustconn-cli secret set now marks the connection vault-backed — storing a vault secret for a connection created by rustconn-cli add left its password source at the None default, so a connect never consulted the vault and the password just stored was never used. secret set now promotes a None source to Vault (an explicit Prompt/Variable/Inherit/Script is left as the user's choice), so the add → set flow produces a connection that actually resolves its credential. (#353)

Changed

  • rustconn-cli secret get mirrors the GUI resolver's from-root search — with "Search from vault root" enabled, secret get --backend keepass now applies the same whole-database fallback (keyed by the connection's scoped key, host and name) the connect path uses, instead of only the scoped RustConn/… lookup. The CLI can now diagnose exactly what a connect would find. (#353)
  • Added diagnostics for the KeePass "Search from vault root" path — when a scoped KeePass lookup misses, RustConn now logs the kdbx_root_search flag value and the preferred backend right before the from-root search gate, and collect_secret_settings logs the read-only / root-search toggle values it collected on save. This turns a "root search never ran" report into a one-line diagnosis of whether the flag reached the connect, while the underlying toggle-persistence issue is tracked. (#353)

Documentation

  • API docs no longer point at code that is gone, and a gate keeps it that way — nothing ran cargo doc, so rustdoc's own lints never fired and 106 warnings had piled up across rustconn-core, rustconn, rustconn-cli and rustconn-dock-sys; 67 of them were links to items that had been renamed, moved or removed. Where the prose had drifted with them it now matches the code: the KeePassXC helpers in secret/status.rs documented a SecretError::Backend variant that does not exist (they return SecretError::KeePassXC), and CairoBackedBuffer::copy_rect claimed to mirror a VncPixelBuffer that is no longer in the tree. Doc examples in the GUI binary used rustconn:: paths, which a binary crate does not have, and now use crate::. A new [workspace.lints.rustdoc] table denies broken intra-doc links and allows public-to-private links, since these docs are read with private items. scripts/verify.sh (default mode) and the CI clippy job now run cargo doc --no-deps --document-private-items with RUSTDOCFLAGS="-D warnings".

Dependencies

  • Updated: dirs 6.0→7.0, tray-icon 0.25.1→0.26.1, muda 0.20.0→0.21.2. dirs 7.0's only breaking change is preference_dir on Windows (RoamingAppData instead of LocalAppData) — RustConn never calls preference_dir and does not target Windows, so the upgrade is a no-op here. tray-icon/muda are macOS-only (behind the tray-macos feature, not built by CI); the deprecated TrayIconBuilder::with_icon_as_template(false) call was dropped in favour of the builder's non-template default (tray-icon 0.26 renamed it to the with_icon_templated opt-in), and muda 0.21's removed TextStyle/libxdo APIs are not used here. All in-range cargo dependencies were already at their latest compatible versions (cargo update changed nothing); cargo deny check advisories is clean.

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

Fedora (.rpm from this release)

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

AppImage

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

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