What's Changed
Security
- Torrent path escape (Windows) — a
.torrentwhose filename carried a drive prefix (C:evil.txt) passed librqbit's traversal check, then discarded the save folder entirely becausePathBuf::pushreplaces the buffer on a prefix; demonstrated writing into the process working directory. Engine patch 0015 (safe_join) refuses any relative path whose components are not allComponent::Normal, at the storage layer, so magnets are covered too. - Proxy leak inventory — all HTTP now goes through one client factory (
src/core/http.rs); pluginhttp_get/fetch/add_urluse it rather than building their own. SOCKS usessocks5h://so names resolve at the proxy. - Dependency audit — RUSTSEC-2026-0258 (h2 0.3, low, DoS) documented in
Cargo.toml: unreachable to fix, since actix-web'srustls-0_23implieshttp2and actix-http prependsh2to ALPN; no newer actix exists.
Network / privacy
- Strict network mode (
network.strict) — switches off whatever the proxy or bound interface cannot cover (DHT, uTP, LSD, UPnP, IPv6), refuses to start when the named interface is absent, pauses every torrent if it disappears while running. Decision logic insrc/core/netguard.rs. - Bind-to-interface on Windows — was a
#[cfg(windows)]stub returningBindDeviceNotSupported, making the whole feature Linux/macOS-only. Engine patch 0014 binds the interface's address instead (strong host model); verified listening on192.168.178.251:6881rather than[::]. ListenerOptions.ipv4_only— the peer listener has its own copy andSessionOptions::ipv4_onlynever reached it, so it bound[::]regardless.- SOCKS5 credentials — username/password were read by the session but settable from no surface; now in Preferences, CLI and the web drawer.
- New settings —
network.strict,network.bind_interface, translated across all 41 locales.
Desktop UI
- Status bar — icons for torrents, DHT nodes, down/up, plus port reachability, proxy-in-use and interface-bound indicators (red when the binding is lost).
- Dialog height clamp —
clamp_to_screenran before the window was realised, soscale_factor()returned 1 andposition()(0,0); on a 200% display it computed a 2024px limit for a 984px screen and never engaged. Now deferred one event-loop turn, and measures the monitor the window is on rather than the primary. - Preferences sizes to the current tab — was
max(tb1..tb7), so every tab inherited the tallest one's height. - Ten-row lists — labels, filters and plugins lists stand ten rows tall instead of collapsing.
- Plugin window — the only window in the codebase with no
screen-limit; now clamped, and re-clamped on every open.
Web interface
- Toolbar parity — add magnet, add torrent, remove, resume, pause, with row selection (which the table had none of).
- Multi-select — ctrl/cmd-click toggles, shift-click ranges; resume/pause act only on the rows they apply to, so a mixed selection does the sensible thing.
- Speed charts — both directions, sharing the desktop's own keys, 96px default, 48–320 range, per-chart grip, double-click resets.
- Resizable columns — persisted server-side in the same
column_statetable the desktop uses (list idwebui), so widths follow the person rather than one browser. - Drag-and-drop adding — hands files to the existing picker, so the batch panes come up unchanged. (Multi-torrent add already worked; it just wasn't findable.)
- Brute-force lockout — configurable attempts / window / block (5 / 60s / 3600s), counted per address; the window and the block are now separate settings rather than one number serving as both.
- Plugins — full folder listing with enabled state, error and permissions; enable/disable with a live host reload; plugin surfaces rendered in the browser from the same state the desktop window uses, so the shipped
rss.rhaiworks there unchanged. The web deliberately cannot approve permissions. - Language sync — changing it in the browser now retranslates the GUI on its next tick.
- Fixes —
api()threw on any empty body (this blanked the plugin panel); duplicate top-levellet selectedwas a SyntaxError that killed the whole script; undefined--ctl-hbroke the header height; progress bar and Actions buttons overflowed their columns; favicon 404. - Cosmetic — boolean settings as lit toggle buttons, setting keys moved to tooltips, app icon in the header, wider add/plugin panels, full-width layout.
Engine patches
- 0014 Windows bind-to-interface (
-sockets, 3 files) — supersedes and retires the old cosmetic 0014. - 0015 torrent path escape (security).
- Series consolidated — 15 numbered features across 20 files and four vendored crates; the whole stack now reverse-applies to pristine crates.io sources with zero markers left (it did not before: 0014's baseline was wrong).
- Docs unstaled —
PATCHES.mdlisted two vendored crates (there are four) and "apply 0001 → 0007"; README claimed "13 features across 16 files".