From 35f07d0a0e6038e874817b3767b83193c6ce730a Mon Sep 17 00:00:00 2001 From: thedancingdeveloper <306930456+thedancingdeveloper@users.noreply.github.com> Date: Wed, 21 Oct 2026 08:24:35 +0000 Subject: [PATCH] chore(release): bump all crates and packages to 0.2.0-beta.2 Bump every crate, the desktop app and the fuzz/benchv2 workspaces, and write the changelog section and release notes for the beta.2 release. --- CHANGELOG.md | 143 ++++++++++++++- Cargo.lock | 28 +-- Cargo.toml | 24 +-- SECURITY.md | 2 +- benchv2/Cargo.lock | 2 +- benchv2/Cargo.toml | 2 +- crates/librtbit-bencode/Cargo.toml | 2 +- crates/librtbit-buffers/Cargo.toml | 2 +- crates/librtbit-clone-to-owned/Cargo.toml | 2 +- crates/librtbit-core/Cargo.toml | 2 +- crates/librtbit-dht/Cargo.toml | 2 +- crates/librtbit-lsd/Cargo.toml | 2 +- crates/librtbit-peer-protocol/Cargo.toml | 2 +- crates/librtbit-sha1-wrapper/Cargo.toml | 2 +- crates/librtbit-tracker-comms/Cargo.toml | 2 +- crates/librtbit-upnp-serve/Cargo.toml | 2 +- crates/librtbit-upnp/Cargo.toml | 2 +- crates/librtbit/Cargo.toml | 2 +- crates/rtbit/Cargo.toml | 2 +- desktop/package.json | 2 +- desktop/src-tauri/Cargo.toml | 2 +- docs/REPOSITORY-LAYOUT.md | 2 +- docs/ReleaseProcess.md | 6 +- docs/releases/v0.2.0-beta.2.md | 214 ++++++++++++++++++++++ fuzz/Cargo.lock | 16 +- fuzz/Cargo.toml | 2 +- package-lock.json | 2 +- scripts/publish.sh | 2 +- 28 files changed, 409 insertions(+), 66 deletions(-) create mode 100644 docs/releases/v0.2.0-beta.2.md diff --git a/CHANGELOG.md b/CHANGELOG.md index b6cfd530..4d24df94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,15 +9,76 @@ upgrade notes in each release describe what to back up and check. ## [Unreleased] -### Fixed - -- WebUI API v2 compat: `torrentcreator/status` now emits `taskID` (was - `taskId`), matching the upstream field name. -- Tests no longer write compat tags into the user's real data directory - (`qbit-tags.json`), which leaked tags between runs. +## [0.2.0-beta.2] - 2026-10-21 ### Added +- Session and API authentication: logins now survive a restart (sessions are + persisted next to the credentials, hashed at rest), and revocable API keys + (`Authorization: Bearer rtb_...`) can be created, listed and deleted through + `GET`/`POST /auth/api_keys` and `DELETE /auth/api_keys/{id}`. A read-only + account role is available for integrations that should not mutate the + session. Sessions are bound to the credential they were issued for, so + changing the admin password signs every existing session out, and logins are + capped at 30 days. +- First-run setup is protected by a one-time setup token, printed in the daemon + log and written to an owner-only `setup-token` file while setup is pending. + Passwords are hashed with argon2, and an existing plaintext + `credentials.json` is migrated automatically. +- An optional TOML configuration file (`--config` or `RTBIT_CONFIG`) for + non-secret settings, with `CLI > environment > file > default` precedence, + an error on unknown keys, and `rtbit config dump` to print the resolved + settings. +- An on-complete hook: a shell command and/or a JSON webhook fired when a + torrent finishes, with `RTBIT_EVENT`, `RTBIT_TORRENT_ID`, `RTBIT_INFO_HASH`, + `RTBIT_TORRENT_NAME`, `RTBIT_OUTPUT_FOLDER` and `RTBIT_COMPLETED_AT` in the + environment. It is not fired for torrents that were already complete when + the session was restored. +- Engine controls for the active-download and active-seed limits, a minimum + free-disk guard before starting a torrent, and `.part` file handling for + in-progress payloads. +- Logging improvements: `--log-file-rotation never|hourly|daily`, + `--log-file-max-files N`, and `--log-format text|json`. +- Operation improvements: an unauthenticated `/healthz` route, a Docker + `HEALTHCHECK`, hardened systemd units (`Restart=on-failure`, + `TimeoutStopSec=30`), and a per-user unit that runs `rtbit` by name. +- A startup banner reporting the Web UI URL, authentication state, state and + download folders, and the listen address. +- Indexarr integration flags: `--indexarr-enabled`, `--indexarr-url`, + `--indexarr-api-key` and their `RTBIT_INDEXARR_*` environment equivalents. +- Desktop OS integration: opening `.torrent` files and magnet links with the + app, forwarding them to the running instance instead of starting a second + one (including Linux `%U` handling), a tray icon, autostart, an updater, and + a themed splash screen with a failure state and retry after a 20 s timeout. +- Web UI accessibility and keyboard work: design tokens and primitives, a + redesigned app shell with a mobile navigation drawer and an "engine + unreachable" panel with retry, labelled toolbar and search controls, an + `aria-pressed` theme toggle, a torrent table with roving tabindex, + `Shift+F10`/context-menu support and `aria-sort` headers, keyboard column + resizing, 44 px rows on coarse pointers, and keyboard-operable torrent + context menus. +- Web UI feature work: settings search, restart markers, an empty state and + expiry notice for the queue, paste and drag-and-drop torrent adding, toasts, + a connection-lost banner, a keyboard shortcuts overlay with view + preferences, and consistent theming and contrast on the feature pages. +- WebUI API v2 compat: the torrent creator now accepts the full task option + set (private, comment, URL seeds, `torrentFilePath`, `startSeeding`, and v2 + or hybrid formats). +- WebUI API v2 compat: sequential download and first/last piece priority are + stored and reported (`toggleSequentialDownload`, + `toggleFirstLastPiecePrio`, `seq_dl`, `f_l_piece_prio`), and `picker` uses + them. +- WebUI API v2 compat: `log/main` and `log/peers` over a bounded in-memory log + ring, and session peer bans through `transfer/banPeers`. +- WebUI API v2 compat: moving and renaming a running torrent now work and are + persisted (`setLocation`, `setSavePath`, `renameFile`, `renameFolder` no + longer require a stopped torrent). +- WebUI API v2 compat: `clientdata/load` and `clientdata/store` over a small + JSON key/value file in the session directory, and + `torrents/properties` now reports `comment`, `created_by` and + `creation_date`. +- WebUI API v2 compat: trackers can be added, edited and removed on a live + torrent, and force-reannounce works without a restart. - Native torrent tags: a session tag registry plus a per-torrent tag set, persisted by the JSON session store (`tags.json` and per-torrent state). The WebUI API v2 compat tag endpoints (`torrents/tags`, `createTags`, @@ -49,6 +110,73 @@ upgrade notes in each release describe what to back up and check. (changed fields only, plus `torrents_removed` / `categories_removed` / `tags_removed`) instead of a full snapshot every poll, and `sync/torrentPeers` is routed with the same rid encoding. +- Packaging: RPM packages (`rtbit--x86_64.rpm`) alongside the Debian + package, a CycloneDX SBOM in every release, and Authenticode signing of the + Windows executable with an RFC 3161 timestamp. `verify-release.sh` checks + the signature and timestamp. +- Packaging: per-release channel manifests for AUR (`rtbit-bin`), Homebrew, + Flatpak (offline, with a signed vendor tarball) and winget. Rendering fails + closed when a digest or placeholder is missing. +- Release verification now requires a valid keyless cosign signature over + `SHA256SUMS` and every listed artefact before the release is published. + +### Changed + +- WebUI API v2 compat coverage grew from 66 to 81 of 97 in-scope endpoints + (36 of them full, 45 partial) across `auth`, `app`, `torrents`, `transfer`, + `sync`, `torrentcreator`, `clientdata` and `log`. `log` and `transfer` are + now fully routed. +- `app/version` reports `v5.0.0` (was `v0.0.1`), which is the version gate + several *arr apps check before enabling features. The advertised + `webapiVersion` is still `2.11.3`. +- Torrent tags moved from `qbit-tags.json` to `tags.json` plus per-torrent + state. A legacy `qbit-tags.json` is imported once at startup. +- `--log-file` now defaults to the `info` filter instead of + `librtbit=debug,info`, so log files are less verbose unless asked. +- The compat layer is split into per-controller modules. This is + behaviour-neutral and internal only. +- Web UI polling is visibility-aware, the speed tab reads from the session + store, and feature pages are loaded lazily, reducing background work while + the tab is hidden. +- The desktop app now builds for Linux and Windows only; macOS bundle targets + were removed. The self-updater is behind the `self-update` feature so the + Flatpak build can omit it. +- The `torrents` table gains columns for queue and share state, `.part` + handling, output-folder roots, file renames and the have-bitfield. They are + added with `ALTER TABLE ... ADD COLUMN IF NOT EXISTS` on startup. + +### Fixed + +- WebUI API v2 compat: `torrentcreator/status` emits `taskID` (was `taskId`), + matching the upstream field name. +- WebUI API v2 compat: `setPreferences` applies speed-limit and seeding-limit + fields partially, ignores unknown fields, and treats `announce_port` as + optional instead of rejecting the whole request. +- WebUI API v2 compat: session IDs expire after one hour of inactivity and + idle sessions are purged, instead of accumulating for the process lifetime. +- Torrents that were queued, held for disk space or paused by a share limit no + longer come back permanently paused after a restart; those flags are + persisted and restored. +- Share limits, the uploaded byte total and the `.part` choice are persisted + correctly, including when they change through the compat API. Session state + is also persisted on a 60 s timer and on shutdown rather than only at + selected points. +- PostgreSQL persistence no longer binds the same parameter twice, and writes + are serialised behind a single lock. +- An on-complete command that hangs is bounded by a timeout, and resuming a + torrent resets its inactivity clock for share limits. +- Tests no longer write compat tags into the user's real data directory + (`qbit-tags.json`), which leaked tags between runs. +- Desktop: the app reads hashed credentials correctly, read-only accounts can + log out, and the CLI no longer consumes the pending setup token. +- Web UI: the `M` shortcut reopens the shortcuts overlay reliably, focus + follows Home/End scrolling, and the overflow menu is named "More options" + and operable from the keyboard. +- Web UI status text meets WCAG AA contrast in both themes (emerald-800, + amber-800 and red-700 on light; red-300 on dark). +- An invalid CORS allow regexp is logged as a warning instead of being + silently ignored. `RTBIT_CORS_ALLOW_REGEXP` takes precedence over the bare + `CORS_ALLOW_REGEXP`. ## [0.1.0-rc.5] - 2026-10-18 @@ -168,7 +296,8 @@ persistent session directory before upgrading. - The Docker build and web UI were consolidated so the shipped interface is built from the reviewed source tree. -[Unreleased]: https://github.com/TheDancingDeveloper-org/rustTorrent/compare/v0.1.0-rc.5...HEAD +[Unreleased]: https://github.com/TheDancingDeveloper-org/rustTorrent/compare/v0.2.0-beta.2...HEAD +[0.2.0-beta.2]: https://github.com/TheDancingDeveloper-org/rustTorrent/releases/tag/v0.2.0-beta.2 [0.1.0-rc.5]: https://github.com/TheDancingDeveloper-org/rustTorrent/releases/tag/v0.1.0-rc.5 [0.1.0-rc.4]: https://github.com/TheDancingDeveloper-org/rustTorrent/releases/tag/v0.1.0-rc.4 [0.1.0-rc.3]: https://github.com/TheDancingDeveloper-org/rustTorrent/releases/tag/v0.1.0-rc.3 diff --git a/Cargo.lock b/Cargo.lock index cb3b5e62..153aed76 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5236,7 +5236,7 @@ dependencies = [ [[package]] name = "rtbit" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" dependencies = [ "anyhow", "bytes", @@ -5270,7 +5270,7 @@ dependencies = [ [[package]] name = "rtbit-desktop" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" dependencies = [ "anyhow", "directories", @@ -6281,7 +6281,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "swarmforge" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" dependencies = [ "anyhow", "arc-swap", @@ -6369,7 +6369,7 @@ dependencies = [ [[package]] name = "swarmforge-bencode" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" dependencies = [ "anyhow", "arrayvec", @@ -6384,7 +6384,7 @@ dependencies = [ [[package]] name = "swarmforge-buffers" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" dependencies = [ "bytes", "serde", @@ -6394,14 +6394,14 @@ dependencies = [ [[package]] name = "swarmforge-clone-to-owned" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" dependencies = [ "bytes", ] [[package]] name = "swarmforge-core" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" dependencies = [ "anyhow", "bytes", @@ -6430,7 +6430,7 @@ dependencies = [ [[package]] name = "swarmforge-dht" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" dependencies = [ "anyhow", "aws-lc-rs", @@ -6462,7 +6462,7 @@ dependencies = [ [[package]] name = "swarmforge-lsd" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" dependencies = [ "anyhow", "atoi 3.1.1", @@ -6482,7 +6482,7 @@ dependencies = [ [[package]] name = "swarmforge-peer-protocol" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" dependencies = [ "anyhow", "bitvec", @@ -6502,7 +6502,7 @@ dependencies = [ [[package]] name = "swarmforge-sha1-wrapper" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" dependencies = [ "assert_cfg", "aws-lc-rs", @@ -6512,7 +6512,7 @@ dependencies = [ [[package]] name = "swarmforge-tracker-comms" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" dependencies = [ "anyhow", "async-stream", @@ -6539,7 +6539,7 @@ dependencies = [ [[package]] name = "swarmforge-upnp" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" dependencies = [ "anyhow", "bstr", @@ -6560,7 +6560,7 @@ dependencies = [ [[package]] name = "swarmforge-upnp-serve" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" dependencies = [ "anyhow", "axum", diff --git a/Cargo.toml b/Cargo.toml index cda42ccc..5a872476 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,18 +46,18 @@ debug = true [workspace.dependencies] # Internal crates. Version-plus-path keeps publishing metadata while making this # monorepo's sources authoritative for all local builds. -librtbit = { version = "0.2.0-beta.1", path = "crates/librtbit", package = "swarmforge", default-features = false } -bencode = { version = "0.2.0-beta.1", path = "crates/librtbit-bencode", package = "swarmforge-bencode", default-features = false } -buffers = { version = "0.2.0-beta.1", path = "crates/librtbit-buffers", package = "swarmforge-buffers" } -clone_to_owned = { version = "0.2.0-beta.1", path = "crates/librtbit-clone-to-owned", package = "swarmforge-clone-to-owned" } -librtbit-core = { version = "0.2.0-beta.1", path = "crates/librtbit-core", package = "swarmforge-core", default-features = false } -dht = { version = "0.2.0-beta.1", path = "crates/librtbit-dht", package = "swarmforge-dht", default-features = false } -librtbit-lsd = { version = "0.2.0-beta.1", path = "crates/librtbit-lsd", package = "swarmforge-lsd", default-features = false } -peer_binary_protocol = { version = "0.2.0-beta.1", path = "crates/librtbit-peer-protocol", package = "swarmforge-peer-protocol", default-features = false } -sha1w = { version = "0.2.0-beta.1", path = "crates/librtbit-sha1-wrapper", package = "swarmforge-sha1-wrapper", default-features = false } -tracker_comms = { version = "0.2.0-beta.1", path = "crates/librtbit-tracker-comms", package = "swarmforge-tracker-comms", default-features = false } -librtbit-upnp = { version = "0.2.0-beta.1", path = "crates/librtbit-upnp", package = "swarmforge-upnp" } -upnp-serve = { version = "0.2.0-beta.1", path = "crates/librtbit-upnp-serve", package = "swarmforge-upnp-serve", default-features = false } +librtbit = { version = "0.2.0-beta.2", path = "crates/librtbit", package = "swarmforge", default-features = false } +bencode = { version = "0.2.0-beta.2", path = "crates/librtbit-bencode", package = "swarmforge-bencode", default-features = false } +buffers = { version = "0.2.0-beta.2", path = "crates/librtbit-buffers", package = "swarmforge-buffers" } +clone_to_owned = { version = "0.2.0-beta.2", path = "crates/librtbit-clone-to-owned", package = "swarmforge-clone-to-owned" } +librtbit-core = { version = "0.2.0-beta.2", path = "crates/librtbit-core", package = "swarmforge-core", default-features = false } +dht = { version = "0.2.0-beta.2", path = "crates/librtbit-dht", package = "swarmforge-dht", default-features = false } +librtbit-lsd = { version = "0.2.0-beta.2", path = "crates/librtbit-lsd", package = "swarmforge-lsd", default-features = false } +peer_binary_protocol = { version = "0.2.0-beta.2", path = "crates/librtbit-peer-protocol", package = "swarmforge-peer-protocol", default-features = false } +sha1w = { version = "0.2.0-beta.2", path = "crates/librtbit-sha1-wrapper", package = "swarmforge-sha1-wrapper", default-features = false } +tracker_comms = { version = "0.2.0-beta.2", path = "crates/librtbit-tracker-comms", package = "swarmforge-tracker-comms", default-features = false } +librtbit-upnp = { version = "0.2.0-beta.2", path = "crates/librtbit-upnp", package = "swarmforge-upnp" } +upnp-serve = { version = "0.2.0-beta.2", path = "crates/librtbit-upnp-serve", package = "swarmforge-upnp-serve", default-features = false } # External crates anyhow = "1" diff --git a/SECURITY.md b/SECURITY.md index f9a6eb1b..dc30f017 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -27,7 +27,7 @@ you in the advisory if you wish. ## Supported versions Security fixes are made against the latest release candidate or release tag -(currently `0.2.0-beta.1`) and the `main` branch. Earlier beta releases are not +(currently `0.2.0-beta.2`) and the `main` branch. Earlier beta releases are not supported; upgrade to the latest tag to receive fixes. ## Deployment notes diff --git a/benchv2/Cargo.lock b/benchv2/Cargo.lock index dafa159f..eff7a467 100644 --- a/benchv2/Cargo.lock +++ b/benchv2/Cargo.lock @@ -102,7 +102,7 @@ checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" [[package]] name = "benchv2" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" dependencies = [ "anyhow", "bollard", diff --git a/benchv2/Cargo.toml b/benchv2/Cargo.toml index b3c4bd9f..c5d770bf 100644 --- a/benchv2/Cargo.toml +++ b/benchv2/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "benchv2" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" edition = "2021" [dependencies] diff --git a/crates/librtbit-bencode/Cargo.toml b/crates/librtbit-bencode/Cargo.toml index f7f13d82..00451f61 100644 --- a/crates/librtbit-bencode/Cargo.toml +++ b/crates/librtbit-bencode/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swarmforge-bencode" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" edition = "2024" description = "Bencode serialization and deserialization using Serde" license = "Apache-2.0" diff --git a/crates/librtbit-buffers/Cargo.toml b/crates/librtbit-buffers/Cargo.toml index b24afb8a..1e8ef08a 100644 --- a/crates/librtbit-buffers/Cargo.toml +++ b/crates/librtbit-buffers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swarmforge-buffers" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" edition = "2024" description = "Utils to work with byte buffers in librtbit source code" license = "Apache-2.0" diff --git a/crates/librtbit-clone-to-owned/Cargo.toml b/crates/librtbit-clone-to-owned/Cargo.toml index 9e5b690e..41da52ac 100644 --- a/crates/librtbit-clone-to-owned/Cargo.toml +++ b/crates/librtbit-clone-to-owned/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swarmforge-clone-to-owned" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" edition = "2024" description = "Util traits to represent something that can be made owned and change type at the same time" license = "Apache-2.0" diff --git a/crates/librtbit-core/Cargo.toml b/crates/librtbit-core/Cargo.toml index 6d36e8ee..0f92621c 100644 --- a/crates/librtbit-core/Cargo.toml +++ b/crates/librtbit-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swarmforge-core" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" edition = "2024" description = "Core types and utilities for the rtbit BitTorrent client" license = "Apache-2.0" diff --git a/crates/librtbit-dht/Cargo.toml b/crates/librtbit-dht/Cargo.toml index 8bb524ef..e2259a20 100644 --- a/crates/librtbit-dht/Cargo.toml +++ b/crates/librtbit-dht/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swarmforge-dht" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" edition = "2024" description = "Kademlia DHT implementation for the rtbit BitTorrent client" license = "Apache-2.0" diff --git a/crates/librtbit-lsd/Cargo.toml b/crates/librtbit-lsd/Cargo.toml index 7f7d7ec5..62d03f0a 100644 --- a/crates/librtbit-lsd/Cargo.toml +++ b/crates/librtbit-lsd/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swarmforge-lsd" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" edition = "2024" description = "BEP 14 Local Service Discovery for the rtbit BitTorrent client" license = "Apache-2.0" diff --git a/crates/librtbit-peer-protocol/Cargo.toml b/crates/librtbit-peer-protocol/Cargo.toml index c432ecb3..0e3d60b8 100644 --- a/crates/librtbit-peer-protocol/Cargo.toml +++ b/crates/librtbit-peer-protocol/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swarmforge-peer-protocol" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" edition = "2024" description = "BitTorrent peer wire protocol implementation for the rtbit client" license = "Apache-2.0" diff --git a/crates/librtbit-sha1-wrapper/Cargo.toml b/crates/librtbit-sha1-wrapper/Cargo.toml index f05411b0..538c0110 100644 --- a/crates/librtbit-sha1-wrapper/Cargo.toml +++ b/crates/librtbit-sha1-wrapper/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swarmforge-sha1-wrapper" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" edition = "2024" description = "Pluggable SHA1/SHA256 abstraction for the rtbit BitTorrent client" license = "Apache-2.0" diff --git a/crates/librtbit-tracker-comms/Cargo.toml b/crates/librtbit-tracker-comms/Cargo.toml index f951592d..a76914f6 100644 --- a/crates/librtbit-tracker-comms/Cargo.toml +++ b/crates/librtbit-tracker-comms/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swarmforge-tracker-comms" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" edition = "2024" description = "HTTP and UDP tracker communication for the rtbit BitTorrent client" license = "Apache-2.0" diff --git a/crates/librtbit-upnp-serve/Cargo.toml b/crates/librtbit-upnp-serve/Cargo.toml index b09188ba..84ab6533 100644 --- a/crates/librtbit-upnp-serve/Cargo.toml +++ b/crates/librtbit-upnp-serve/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swarmforge-upnp-serve" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" edition = "2024" description = "Simple UPnP MediaServer implementation for the rtbit BitTorrent client" license = "Apache-2.0" diff --git a/crates/librtbit-upnp/Cargo.toml b/crates/librtbit-upnp/Cargo.toml index 5a393c4e..1bb81979 100644 --- a/crates/librtbit-upnp/Cargo.toml +++ b/crates/librtbit-upnp/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swarmforge-upnp" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" edition = "2024" description = "UPnP port forwarding client for the rtbit BitTorrent client" license = "Apache-2.0" diff --git a/crates/librtbit/Cargo.toml b/crates/librtbit/Cargo.toml index 6e2485cb..71e5fb23 100644 --- a/crates/librtbit/Cargo.toml +++ b/crates/librtbit/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swarmforge" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" edition = "2024" description = "Core BitTorrent client library for the rtbit torrent client" license = "Apache-2.0" diff --git a/crates/rtbit/Cargo.toml b/crates/rtbit/Cargo.toml index 33938994..6f4bfc8e 100644 --- a/crates/rtbit/Cargo.toml +++ b/crates/rtbit/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtbit" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" authors = ["AusAgentSmith "] edition = "2024" description = "A bittorrent command line client and server." diff --git a/desktop/package.json b/desktop/package.json index 4e6e41d5..2ca240a2 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -1,7 +1,7 @@ { "name": "rtbit-desktop", "private": true, - "version": "0.2.0-beta.1", + "version": "0.2.0-beta.2", "scripts": { "tauri": "tauri" }, diff --git a/desktop/src-tauri/Cargo.toml b/desktop/src-tauri/Cargo.toml index dbed0c61..1ce68362 100644 --- a/desktop/src-tauri/Cargo.toml +++ b/desktop/src-tauri/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rtbit-desktop" edition = "2024" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" description = "rtbit torrent client" license = "" repository = "" diff --git a/docs/REPOSITORY-LAYOUT.md b/docs/REPOSITORY-LAYOUT.md index b056626e..87726d82 100644 --- a/docs/REPOSITORY-LAYOUT.md +++ b/docs/REPOSITORY-LAYOUT.md @@ -16,7 +16,7 @@ similar are kept separate. Architecture notes live in the other files under | `benchv2/` | Rust-native benchmark harness comparing rtbit with another client. Outside the workspace, with its own `Cargo.toml`, `Dockerfile` and `docker-compose.yml`. | All crates and packages share the version in the release notes, currently -`0.2.0-beta.1`. `scripts/check-repo-hygiene.sh` (run with `make check-repo`) fails +`0.2.0-beta.2`. `scripts/check-repo-hygiene.sh` (run with `make check-repo`) fails if a manifest drifts from it. ## Container images and compose files diff --git a/docs/ReleaseProcess.md b/docs/ReleaseProcess.md index 0a37632b..1a1f1238 100644 --- a/docs/ReleaseProcess.md +++ b/docs/ReleaseProcess.md @@ -5,11 +5,11 @@ rusttorrent.dev website. The historical Forgejo/Woodpecker path is retired. ## Versioning -The current pre-release is `0.2.0-beta.1`. +The current pre-release is `0.2.0-beta.2`. - Crate version: `crates/rtbit/Cargo.toml` -- Release tag: `v0.2.0-beta.1` -- Docker tag: `ghcr.io/thedancingdeveloper-org/rusttorrent:v0.2.0-beta.1` +- Release tag: `v0.2.0-beta.2` +- Docker tag: `ghcr.io/thedancingdeveloper-org/rusttorrent:v0.2.0-beta.2` ## Branching model diff --git a/docs/releases/v0.2.0-beta.2.md b/docs/releases/v0.2.0-beta.2.md new file mode 100644 index 00000000..fd03bd83 --- /dev/null +++ b/docs/releases/v0.2.0-beta.2.md @@ -0,0 +1,214 @@ +# rustTorrent v0.2.0-beta.2 + +## Summary + +rustTorrent 0.2.0-beta.2 turns the Web UI into something usable without a mouse +and substantially widens the WebUI API v2 compatibility layer. It adds +persistent sessions, revocable API keys, a read-only role, native torrent tags, +queue ordering with force-start, per-torrent speed limits, and live move and +rename of running torrents. + +It also reworks persistence so queue, disk and share-limit state survives a +restart, adds an on-complete command and webhook, and rounds out packaging with +RPM packages, signed Windows binaries, an SBOM and channel manifests. + +This remains beta software. Back up the persistent session directory and the +PostgreSQL database before upgrading, and avoid using it for data that cannot +be downloaded again. + +## What changed since 0.1.0-rc.1 + +- **Web UI API v2 compat** grew from 66 to 81 of 97 in-scope endpoints, 36 of + them full, across `auth`, `app`, `torrents`, `transfer`, `sync`, + `torrentcreator`, `clientdata` and `log`. `transfer` and `log` are now fully + routed. +- **Authentication** is persisted across restarts, gains revocable API keys and + a read-only role, and first-run setup is protected by a one-time setup token. +- **The engine** gains an on-complete hook, active-download and active-seed + limits, a minimum free-disk guard, `.part` handling, and full live move and + rename of running torrents. +- **The desktop app** opens `.torrent` files and magnet links from the OS, + forwards them to a single running instance, and adds a tray icon, autostart, + an updater and a themed splash screen. +- **The web UI** is keyboard and screen-reader accessible throughout: a roving + tabindex torrent table, `aria-sort` headers, context menus on `Shift+F10`, + 44 px rows on coarse pointers, a mobile navigation drawer, and WCAG AA status + colours in both themes. +- **Packaging** adds RPM packages, Authenticode-signed Windows executables, a + CycloneDX SBOM, and AUR, Homebrew, Flatpak and winget manifests rendered per + release. + +## Upgrade notes + +- Back up `/home/rtbit/db`, `/home/rtbit/cache` and the credentials directory + (which now also holds `sessions.json` and `api_keys.json`) before upgrading. +- **First-run setup now requires a setup token.** It is printed in the daemon + log and written to an owner-only `setup-token` file while setup is pending. + Scripted provisioning that posts to the setup endpoint must pass it. The + token is single-use and is not consumed by the CLI. +- **Existing passwords are migrated automatically.** A plaintext + `credentials.json` is rewritten with an argon2 hash on first start. Changing + the admin password or read-only account signs out every existing session, + and logins are capped at 30 days. +- **The PostgreSQL schema gains columns.** Queue, disk-hold and share-limit + state, the have-bitfield, output-folder roots, file renames and the + uploaded byte total are added with `ALTER TABLE ... ADD COLUMN IF NOT EXISTS` + at startup. This is additive and non-destructive, but back up the database + first. Older binaries ignore the new columns when downgrading. +- **Tag storage moved** from `qbit-tags.json` to `tags.json` plus per-torrent + state. The legacy file is imported once at startup and left in place. +- **Log files are less verbose by default.** `--log-file` now uses the `info` + filter instead of `librtbit=debug,info`. Pass an explicit filter to restore + the old detail, and use `--log-format json` for structured logs. +- **`app/version` now reports `v5.0.0`** (was `v0.0.1`), because *arr apps gate + features on it. The advertised `webapiVersion` is unchanged at `2.11.3`. +- **macOS is no longer a desktop bundle target.** Linux and Windows are + supported. The self-updater is a `self-update` feature and is disabled in the + Flatpak build. +- For migrations from another client, use `--storage-read-only` for the first + verification pass and confirm the payload root expected by each imported + torrent. That behaviour is unchanged from 0.1.0-rc.1. +- `latest` and `beta` move to this release after publication. Pin + `v0.2.0-beta.2` when reproducibility matters. + +## Added + +- Persistent sessions (hashed at rest and bound to the credential that issued + them) and revocable API keys (`Bearer rtb_...`) through `GET`/`POST + `/auth/api_keys` and `DELETE /auth/api_keys/{id}`, plus a read-only role. +- A one-time first-run setup token and argon2 password hashing, with automatic + migration of a plaintext `credentials.json`. +- An optional TOML config file (`--config` or `RTBIT_CONFIG`) for non-secret + settings, with `CLI > environment > file > default` precedence, unknown keys + rejected, and `rtbit config dump`. +- An on-complete shell command and JSON webhook with `RTBIT_EVENT`, + `RTBIT_TORRENT_ID`, `RTBIT_INFO_HASH`, `RTBIT_TORRENT_NAME`, + `RTBIT_OUTPUT_FOLDER` and `RTBIT_COMPLETED_AT`. It does not fire for torrents + that were already complete when the session was restored. +- Active-download and active-seed limits, a minimum free-disk guard, and + `.part` handling for in-progress payloads. +- `--log-file-rotation never|hourly|daily`, `--log-file-max-files N` and + `--log-format text|json`. +- An unauthenticated `/healthz` route, a Docker `HEALTHCHECK`, hardened systemd + units, and a per-user unit that runs `rtbit` by name. +- A startup banner reporting the Web UI URL, auth state, folders and listen + address, and Indexarr flags (`--indexarr-enabled`, `--indexarr-url`, + `--indexarr-api-key`, plus `RTBIT_INDEXARR_*`). +- Desktop OS integration: open `.torrent` and magnet links, single-instance + forwarding, Linux `%U` handling, tray, autostart, updater and a themed splash + screen with a failure state and retry. +- Web UI accessibility: design tokens and primitives, a mobile navigation + drawer, an "engine unreachable" panel with retry, labelled toolbar and search + controls, an `aria-pressed` theme toggle, a roving-tabindex torrent table + with `Shift+F10`/context menus, `aria-sort` headers, keyboard column + resizing, and 44 px rows on coarse pointers. +- Web UI features: settings search, restart markers, queue empty state and + expiry notice, paste and drag-and-drop adding, toasts, a connection-lost + banner, a keyboard shortcuts overlay with view preferences, and consistent + feature-page theming. +- WebUI API v2 compat: full torrent-creator task options (private, comment, + URL seeds, `torrentFilePath`, `startSeeding`, v2 and hybrid formats). +- WebUI API v2 compat: sequential download and first/last piece priority + (`toggleSequentialDownload`, `toggleFirstLastPiecePrio`, `seq_dl`, + `f_l_piece_prio`), honoured by `picker`. +- WebUI API v2 compat: `log/main` and `log/peers` over a bounded log ring, and + session peer bans through `transfer/banPeers`. +- WebUI API v2 compat: live move and rename of running torrents (`setLocation`, + `setSavePath`, `renameFile`, `renameFolder`), persisted across reloads. +- WebUI API v2 compat: `clientdata/load` and `clientdata/store`, and + `comment`, `created_by` and `creation_date` in `torrents/properties`. +- WebUI API v2 compat: live tracker add, edit and remove, with forced + reannounce. +- Native torrent tags: a session tag registry and per-torrent tag set persisted + in `tags.json` and per-torrent state, used by the compat tag endpoints, the + `torrents/info` `tags` field and `tag` filter, and `torrents/add`. +- Torrent queue ordering and force-start: a persisted queue position followed + by the policy pass, force-started torrents outside the limits, and + `topPrio`/`bottomPrio`/`increasePrio`/`decreasePrio`, `setForceStart`, the + `queuedDL`/`queuedUP`/`forcedDL`/`forcedUP` states, and queueing preferences. +- Per-torrent speed limits saved across restarts, a native + `GET`/`POST /torrents/{id}/limits`, and `dl_limit`/`up_limit` reporting. +- Session speed limits through `transfer/getSpeedLimits` and + `transfer/setSpeedLimits`, and real `dht_nodes` in `transfer/info` and + `sync/maindata`. +- A `sync/maindata` rid delta protocol (changed fields plus `*_removed` lists) + and `sync/torrentPeers` with the same rid encoding. +- WebUI API v2 compat conformance tests: a response contract for every routed + endpoint in `qbit_parity_spec.json`, validated against a live torrent, plus + an add/stop/start/recheck/setCategory/delete lifecycle test. +- RPM packages alongside the Debian package, a CycloneDX SBOM, and + Authenticode signing of the Windows executable with an RFC 3161 timestamp, + verified by `verify-release.sh`. +- AUR (`rtbit-bin`), Homebrew, Flatpak (offline, with a signed vendor tarball) + and winget manifests rendered per release, failing closed when a digest or + placeholder is missing. +- Keyless cosign verification of `SHA256SUMS` and every listed artefact before + a release is published. + +## Changed + +- WebUI API v2 compat coverage grew from 66 to 81 of 97 in-scope endpoints (36 + full, 45 partial). `transfer` and `log` are now fully routed. +- `app/version` reports `v5.0.0`; `webapiVersion` remains `2.11.3`. +- Torrent tags moved from `qbit-tags.json` to `tags.json` plus per-torrent + state, with a one-time import of the legacy file. +- `--log-file` defaults to the `info` filter instead of + `librtbit=debug,info`. +- The compat layer is split into per-controller modules; this is + behaviour-neutral and internal. +- Web UI polling is visibility-aware, the speed tab reads from the session + store, and feature pages load lazily. +- The desktop app targets Linux and Windows only; macOS bundle targets were + removed and the self-updater moved behind the `self-update` feature. +- The `torrents` table gains additive columns for queue and share state, + `.part` handling, output-folder roots, file renames and the have-bitfield. + +## Fixed + +- `torrentcreator/status` emits `taskID` (was `taskId`), matching upstream. +- `setPreferences` applies speed and seeding limits partially, ignores unknown + fields, and accepts a missing `announce_port` instead of rejecting the + request. +- Session IDs expire after one hour of inactivity and idle sessions are + purged. +- Torrents that were queued, held for disk space or paused by a share limit no + longer come back permanently paused after a restart. +- Share limits, the uploaded byte total and the `.part` choice persist + correctly. State is also saved on a 60 s timer and at shutdown. +- PostgreSQL persistence no longer binds a parameter twice, and writes are + serialised behind a single lock. +- A hanging on-complete command is bounded by a timeout, and resuming a + torrent resets the share-limit inactivity clock. +- Desktop reads hashed credentials correctly, read-only accounts can log out, + and the CLI no longer consumes the pending setup token. +- The `M` shortcut reopens the shortcuts overlay reliably, focus follows + Home/End scrolling, and the overflow menu is named "More options" and + keyboard operable. +- Status text meets WCAG AA contrast in both themes. +- An invalid CORS allow regexp is logged as a warning; `RTBIT_CORS_ALLOW_REGEXP` + takes precedence over the bare `CORS_ALLOW_REGEXP`. +- Tests no longer write compat tags into the user's real data directory. + +## Validation + +- `cargo fmt --all -- --check` +- `cargo check --workspace --exclude rtbit-desktop --no-default-features --features default-tls` +- `cargo test --workspace --exclude rtbit-desktop --no-default-features --features default-tls` +- `cargo clippy --workspace --exclude rtbit-desktop --no-default-features --features default-tls -- -D warnings` +- Web UI unit tests, lint, production build, and Playwright browser tests +- Website structural validation +- GitHub release binary build and multi-architecture container publication + +## Downloads + +- Linux x86_64: `rtbit-v0.2.0-beta.2-linux-x86_64` +- Windows x86_64: `rtbit-v0.2.0-beta.2-windows-x86_64.exe` +- Debian/Ubuntu amd64: `rtbit-v0.2.0-beta.2-amd64.deb` +- Fedora/RHEL x86_64: `rtbit-v0.2.0-beta.2-x86_64.rpm` +- SBOM: `rtbit-v0.2.0-beta.2-sbom.cdx.json` +- Checksums: `SHA256SUMS-v0.2.0-beta.2.txt` +- Docker: `ghcr.io/thedancingdeveloper-org/rusttorrent:v0.2.0-beta.2` +- Source: automatic `.zip` and `.tar.gz` archives on the GitHub release tag + +Release files are attached to the canonical GitHub release and are also +published at `https://dl.rusttorrent.dev/v0.2.0-beta.2/`. diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index cd6cdb1a..4100bc71 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -980,7 +980,7 @@ dependencies = [ [[package]] name = "rusttorrent-fuzz" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" dependencies = [ "libfuzzer-sys", "swarmforge-bencode", @@ -1085,7 +1085,7 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "swarmforge-bencode" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" dependencies = [ "anyhow", "arrayvec", @@ -1100,7 +1100,7 @@ dependencies = [ [[package]] name = "swarmforge-buffers" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" dependencies = [ "bytes", "serde", @@ -1110,14 +1110,14 @@ dependencies = [ [[package]] name = "swarmforge-clone-to-owned" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" dependencies = [ "bytes", ] [[package]] name = "swarmforge-core" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" dependencies = [ "anyhow", "bytes", @@ -1145,7 +1145,7 @@ dependencies = [ [[package]] name = "swarmforge-dht" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" dependencies = [ "anyhow", "aws-lc-rs", @@ -1176,7 +1176,7 @@ dependencies = [ [[package]] name = "swarmforge-peer-protocol" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" dependencies = [ "anyhow", "bitvec", @@ -1195,7 +1195,7 @@ dependencies = [ [[package]] name = "swarmforge-sha1-wrapper" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" dependencies = [ "assert_cfg", "crypto-hash", diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index ce1ff288..7c6c8eac 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rusttorrent-fuzz" -version = "0.2.0-beta.1" +version = "0.2.0-beta.2" publish = false edition = "2024" diff --git a/package-lock.json b/package-lock.json index 4ff961d8..301f7758 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ }, "desktop": { "name": "rtbit-desktop", - "version": "0.2.0-beta.1", + "version": "0.2.0-beta.2", "devDependencies": { "@tauri-apps/cli": "^2.12.3" } diff --git a/scripts/publish.sh b/scripts/publish.sh index 94faa257..bc3e7b0d 100755 --- a/scripts/publish.sh +++ b/scripts/publish.sh @@ -20,7 +20,7 @@ if $resume && [[ -n "$publish_flag" ]]; then exit 2 fi -version="0.2.0-beta.1" +version="0.2.0-beta.2" # Pre-release versions (a '-' suffix such as 0.1.0-rc.1) are never published to # crates.io from this script. Exit 0 so a release pipeline that calls it for every