Skip to content

Dev 2.10.0 - #198

Merged
jordanlambrecht merged 137 commits into
mainfrom
development
Aug 19, 2026
Merged

Dev 2.10.0#198
jordanlambrecht merged 137 commits into
mainfrom
development

Conversation

@jordanlambrecht

Copy link
Copy Markdown
Owner

No description provided.

jordanlambrecht and others added 30 commits August 13, 2026 14:55
qBittorrent 5.2.3RC returns 204 with an empty body on successful
/api/v2/auth/login instead of the pre-5.2 200 "Ok." body, which was
incorrectly treated as a failed login and surfaced as a generic
"Connection failed" error.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
qBittorrent 5.2+ names its session cookie QBT_SID_<port> (its own
WebUI listen port baked into the name) instead of the legacy plain
SID, so the /SID=([^;]+)/ regex in login() never matched and auth
kept failing even after the 204-status fix. Widen it to match any
cookie whose name contains SID as a token.

Verified live against a 5.2+ instance that the server accepts the
session value back under any cookie name (only the value is
validated, not the name), so qbtFetch's Cookie: SID=${sid} header
needs no change.
… SID

qBittorrent 5.2+ rejects the session value when sent back under the wrong
cookie name (verified live: same SID value, QBT_SID_8080=<value> -> 200,
SID=<value> -> 403). login() now returns {name, value} captured from the
Set-Cookie regex match instead of just the value, and that pair is plumbed
through sidCache/getSession/withSessionRetry/qbtFetch so the Cookie header
uses the actual assigned name.
The regex-over-comma-joined-header approach could pick the wrong cookie
(any name merely containing "SID", e.g. "SIDCC") and could bleed a cookie's
value across a comma boundary into the next Set-Cookie entry when the SID
cookie had no trailing attributes. getSetCookie() returns each Set-Cookie
header as its own array element, so each is parsed as a single cookie and
matched against an exact SID/QBT_SID_<port> name pattern.
fix(auth): support qBittorrent 5.2+ login and session cookie
- New registry entry (UNIT3D platform)
- Uses existing Unit3dAdapter

- Fixed: was listed as Gazelle 'Unvalidated' — never worked
- New custom BTN JSON-RPC adapter (platform: 'btn')
- POST JSON-RPC to api.broadcasthe.net, maps Lumens→seedbonus
- Un-stucks the BTN entry — now fully functional

- New custom adapter (cookie + HTML scrape)
- Parses .tTipWrap/.tTip header stats and .up-stat cards
- Credential format: {cookies, userAgent} JSON

- New custom adapter (username/password login + HTML scrape)
- POSTs to /user/account/login/, captures tluid/tlpass cookies
- Parses .profile-*-details spans from profile page
- Credential format: {username, password} JSON

- 7 new files, 6 edited files
- All 2848 tests pass (78 new)
- TypeScript and biome lint clean
H1: mark Class, Lumens, Bonus, HnR, JoinDate as optional in
BtnUserInfoResult. use nullish coalescing fallbacks in mapBtnResult
so adapter degrades gracefully if BTN changes API response shape.

H2: replace BigInt(parseInt()) with BigInt(string) to preserve
full precision for byte values exceeding Number.MAX_SAFE_INTEGER.

add test for missing optional fields scenario.

Fixes: QA H1+H2
parseBytes: return 0n for ∞/Inf/-∞/-Inf values so UNIT3D
trackers (e.g. zenith) that return infinite buffer don't crash
the poll with 'Invalid byte format' error.

iptorrents: inspect Location header on 302 rather than throwing
session-expired on every redirect. iptorrents 302s logged-in
users from / to /t — only throw when redirected to a login page.
follow non-login redirects up to 3 hops.

add 6 new tests (4 parseBytes ∞ variants, 2 ipt redirect).
2855 total tests pass, tsc clean.

Fixes: 86bae41991a748
- H1: Handle infinity values case-insensitively (e.g. 'inf', 'INF').
- H2: Fix relative redirect resolution in IPTorrents fetchHtml.
- Added tests for case-insensitive infinity and path-relative redirects.

Fixes: 86bae41991a748
Postgres freeleech_tokens/seedbonus columns are INTEGER; parseFloat on
BTN's Bonus/Lumens fields produced decimals once tokens accrued
fractional values, causing every snapshot INSERT to throw and BTN to
auto-pause after 4 consecutive failed polls (failing since 2026-07-26).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…x stale test

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…r offline

Derives ratio from byte totals in every adapter rather than trusting each
site's own field, and carries a ratioIsInfinite flag across the JSON boundary
so it stays distinguishable from missing data.

Closes #172
Closes #154
… one

Reports client count and the number of untagged torrents so the empty state
can distinguish no client, a connected client with nothing tagged, and a
genuinely quiet day.

Refs #157
jordanlambrecht and others added 11 commits August 18, 2026 00:53
Bumps [@commitlint/config-conventional](https://github.com/conventional-changelog/commitlint/tree/HEAD/@commitlint/config-conventional) from 20.5.3 to 21.2.2.
- [Release notes](https://github.com/conventional-changelog/commitlint/releases)
- [Changelog](https://github.com/conventional-changelog/commitlint/blob/master/@commitlint/config-conventional/CHANGELOG.md)
- [Commits](https://github.com/conventional-changelog/commitlint/commits/v21.2.2/@commitlint/config-conventional)

---
updated-dependencies:
- dependency-name: "@commitlint/config-conventional"
  dependency-version: 21.2.2
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [react](https://github.com/react/react/tree/HEAD/packages/react) from 19.2.5 to 19.2.8.
- [Release notes](https://github.com/react/react/releases)
- [Changelog](https://github.com/react/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/react/react/commits/v19.2.8/packages/react)

---
updated-dependencies:
- dependency-name: react
  dependency-version: 19.2.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
@gitguardian

gitguardian Bot commented Aug 18, 2026

Copy link
Copy Markdown

⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

🔎 Detected hardcoded secret in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
36197941 Triggered Username Password 4b40115 src/app/api/clients/client-routes.test.ts View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secret safely. Learn here the best practices.
  3. Revoke and rotate this secret.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

@jordanlambrecht jordanlambrecht changed the title Dev 2.9.0 Dev 2.10.0 Aug 18, 2026
Comment thread src/lib/download-clients/qbt/transport.ts Dismissed
…development/react-19.2.8

chore(deps): bump react from 19.2.5 to 19.2.8
…development/commitlint/config-conventional-21.2.2

chore(deps-dev): bump @commitlint/config-conventional from 20.5.3 to 21.2.2
@github-actions

Copy link
Copy Markdown

Knip Code Analysis

Found 128 total issues

Category Count
Unused Dependencies 1
Unused Dev Dependencies 4
Unused Exports 60
Unused Types 63
View details

Run pnpm knip locally to see the full report.

Use pnpm knip:filter pattern to filter results by file path.


Use /** @public */ JSDoc tags to mark intentionally exported symbols.

@github-actions

Copy link
Copy Markdown

⚠️ Tracker registry warnings

Aither (`aither`) — Warnings (2)
Field Status
Missing notableMembers ⚠️ Warning
Missing stats ⚠️ Warning
BroadcasTheNet (`broadcasthenet`) — Warnings (6)
Field Status
Missing userClasses ⚠️ Warning
Missing releaseGroups ⚠️ Warning
Missing notableMembers ⚠️ Warning
Missing bannedGroups ⚠️ Warning
Missing stats ⚠️ Warning
Missing rules.fullRulesMarkdown ⚠️ Warning
FearNoPeer (`fearnopeer`) — Warnings (1)
Field Status
Missing notableMembers ⚠️ Warning
HAWKE-UNO (`hawkeuno`) — Warnings (6)
Field Status
Missing userClasses ⚠️ Warning
Missing releaseGroups ⚠️ Warning
Missing notableMembers ⚠️ Warning
Missing bannedGroups ⚠️ Warning
Missing stats ⚠️ Warning
Missing rules.fullRulesMarkdown ⚠️ Warning
IPTorrents (`iptorrents`) — Warnings (9)
Field Status
profileUrlPattern defined but supportsTransitPapers is not true ⚠️ Warning
Missing userClasses ⚠️ Warning
Missing releaseGroups ⚠️ Warning
Missing notableMembers ⚠️ Warning
Missing bannedGroups ⚠️ Warning
Missing stats ⚠️ Warning
Missing rules.fullRulesMarkdown ⚠️ Warning
Missing logo ⚠️ Warning
Missing trackerHubSlug ⚠️ Warning
Phoenix Project (`phoenixproject`) — Warnings (4)
Field Status
Missing releaseGroups ⚠️ Warning
Missing notableMembers ⚠️ Warning
Missing bannedGroups ⚠️ Warning
Missing trackerHubSlug ⚠️ Warning
REDacted (`redacted`) — Warnings (5)
Field Status
Missing releaseGroups ⚠️ Warning
Missing notableMembers ⚠️ Warning
Missing bannedGroups ⚠️ Warning
Missing stats ⚠️ Warning
Missing logo ⚠️ Warning
seedpool (`seedpool`) — Warnings (8)
Field Status
Missing specialty ⚠️ Warning
Missing releaseGroups ⚠️ Warning
Missing notableMembers ⚠️ Warning
Missing bannedGroups ⚠️ Warning
Missing stats ⚠️ Warning
Missing rules.fullRulesMarkdown ⚠️ Warning
Missing logo ⚠️ Warning
Missing trackerHubSlug ⚠️ Warning
SkipTheCommercials (`skipthecommercials`) — Warnings (2)
Field Status
Missing bannedGroups ⚠️ Warning
Missing trackerHubSlug ⚠️ Warning
TorrentLeech (`torrentleech`) — Warnings (8)
Field Status
profileUrlPattern defined but supportsTransitPapers is not true ⚠️ Warning
Missing userClasses ⚠️ Warning
Missing releaseGroups ⚠️ Warning
Missing notableMembers ⚠️ Warning
Missing bannedGroups ⚠️ Warning
Missing stats ⚠️ Warning
Missing rules.fullRulesMarkdown ⚠️ Warning
Missing logo ⚠️ Warning
Upload.cx (`uploadcx`) — Warnings (2)
Field Status
Missing stats ⚠️ Warning
Missing trackerHubSlug ⚠️ Warning
Zenith (`zenith`) — Warnings (9)
Field Status
profileUrlPattern defined but supportsTransitPapers is not true ⚠️ Warning
Missing userClasses ⚠️ Warning
Missing releaseGroups ⚠️ Warning
Missing notableMembers ⚠️ Warning
Missing bannedGroups ⚠️ Warning
Missing stats ⚠️ Warning
Missing rules.fullRulesMarkdown ⚠️ Warning
Missing logo ⚠️ Warning
Missing trackerHubSlug ⚠️ Warning

Allowed content categories: Movies, TV, Music, Games, Apps, Sports, Books, Audiobooks, Comics, Manga, Anime, XXX, Documentaries, Education, Tutorials, Fanres

See src/data/__tests__/tracker-registry.test.ts for all validation rules.

@github-actions

Copy link
Copy Markdown

✅ Security audit passed

Passed (38/38)

  • ✅ Auth enforcement on protected routes (per-handler)
  • ✅ No dangerous functions (eval, innerHTML, etc.)
  • ✅ No hardcoded secrets in source
  • ✅ Security headers in next.config.ts
  • ✅ Cookie security (httpOnly, sameSite, secure)
  • ✅ No sensitive fields in API responses
  • ✅ No .env files committed to repo
  • ✅ No raw SQL in API routes
  • ✅ No fetch/redirect with unvalidated URLs in routes
  • ✅ Timing-safe comparison for secret values
  • ✅ No raw SQL migration files (schema-first only)
  • ✅ External fetch calls have timeouts
  • ✅ Docker container runs as non-root user
  • ✅ Public routes match proxy allowlist
  • ✅ File delete operations have path traversal defense
  • ✅ Password hashing uses Argon2 (not SHA-256/bcrypt)
  • ✅ Encrypted columns written via encrypt()
  • ✅ TOTP 2FA flow integrity
  • ✅ Emergency lockdown flow integrity
  • ✅ Scrub & delete (nuke) flow integrity
  • ✅ Backup restore flow integrity
  • ✅ Login flow integrity
  • ✅ Auth result checked before proceeding
  • ✅ Backup password inputs bounded before key derivation
  • ✅ Webhook delivery fetch uses redirect: "error"
  • ✅ SESSION_SECRET minimum-length guard in auth/crypto modules
  • ✅ Notification URL validators include SSRF protection
  • ✅ Dockerfile does not COPY sensitive files
  • ✅ No secret env vars in client components
  • ✅ Adapter Cookie headers guard against injection
  • ✅ Adapter files do not log credential values
  • ✅ No console.log in API routes
  • ✅ No TODO/FIXME in security-critical files
  • ✅ JSON.parse wrapped in try-catch
  • ✅ No swallowed errors in catch blocks
  • ✅ Request body size validation on upload routes
  • ✅ BigInt fields use string serialization
  • ✅ No raw error messages in API responses

Summary: 38/38 checks passed

See scripts/security-audit.ts for check definitions and SECURITY.md for the full security architecture.

@jordanlambrecht
jordanlambrecht merged commit 8be42b8 into main Aug 19, 2026
10 of 11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants