Skip to content

fix(tracker-adapters): correct TL downloaded bytes and user class parsing - #3

Merged
patrickdundas merged 1 commit into
mainfrom
fix/tl-profile-parsing
Jul 29, 2026
Merged

fix(tracker-adapters): correct TL downloaded bytes and user class parsing#3
patrickdundas merged 1 commit into
mainfrom
fix/tl-profile-parsing

Conversation

@patrickdundas

Copy link
Copy Markdown
Owner

Two parsing bugs found by comparing a real logged-in TL profile page against what the adapter actually wrote to the DB. Both produced confidently wrong data rather than errors, so neither surfaced without that comparison.

downloaded read as 0 bytes

TL's markup is inconsistent — uploaded and ratio carry a specific class, downloaded does not:

uploaded:   <span class="profile-info-details profile-uploaded-details">2.39 TB</span>
downloaded: <span class="profile-info-details">244.44 GB</span>

.profile-downloaded-details therefore matched nothing. This also corrupted bufferBytes (uploaded − downloaded), which reported the entire uploaded figure as buffer. Now falls back to scoping by the wrapper div.

User class read as "ic TL"

The body-text regex scans the whole document and reaches the nav menu's "Classic TL" link long before the real field — "Class" matches inside "Classic", capturing "ic TL". Replaced with the .label-user-class badge, falling back to the profile table's Class row. Now reads "Super User".

Verification

Observed live before this fix: downloaded=0 bytes, group_name="ic TL". Both now covered by regression tests built from the real markup, including the nav menu that caused the collision. 20 tests pass; tsc and biome clean.

Version bumped to 2.8.9-homelab.2 so the release publishes.

🤖 Generated with Claude Code

…sing

Two parsing bugs surfaced by a real logged-in TorrentLeech profile page. Both
produced confidently wrong data rather than errors, so neither was visible
without comparing against the live page.

downloaded read as 0 bytes. TL's markup is inconsistent: the uploaded and
ratio spans carry both `profile-info-details` and a specific
`profile-*-details` class, but the downloaded span only carries the generic
one:

  uploaded:   <span class="profile-info-details profile-uploaded-details">
  downloaded: <span class="profile-info-details">

So `.profile-downloaded-details` matched nothing. This also corrupted
bufferBytes, computed as uploaded minus downloaded, which reported the full
uploaded figure as buffer. Now falls back to scoping by the wrapper div.

User class read as "ic TL". The previous body-text regex scans the whole
document and hits the "Classic TL" link in the nav menu long before the real
field - "Class" matches inside "Classic", capturing "ic TL". Replaced with
the `.label-user-class` badge, falling back to the profile table's Class row.
Correctly reads "Super User".

Tests use the real markup shapes, including the nav menu that caused the
class collision, so both are covered by regression guards.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Knip Code Analysis

Found 8 total issues

Category Count
Unused Dependencies 1
Unused Dev Dependencies 3
Unused Exports 4
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

🚫 Security audit failed

Critical Failures

Check File Details
External fetch calls have timeouts src/lib/adapters/btn.ts:69 fetch() call without a timeout signal — add signal: AbortSignal.timeout(ms)

Warnings

Check File Details
No swallowed errors in catch blocks src/lib/adapters/iptorrents.ts:108 catch block swallows error without logging or re-throwing
No swallowed errors in catch blocks src/lib/adapters/iptorrents.ts:114 catch block swallows error without logging or re-throwing
No swallowed errors in catch blocks src/lib/adapters/iptorrents.ts:175 catch block swallows error without logging or re-throwing
No swallowed errors in catch blocks src/lib/adapters/iptorrents.ts:181 catch block swallows error without logging or re-throwing

Passed (36/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)
  • ✅ 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
  • ✅ Request body size validation on upload routes
  • ✅ BigInt fields use string serialization
  • ✅ No raw error messages in API responses

Summary: 36/38 checks passed
1 critical failure(s)
— 1 warning(s)

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

@patrickdundas
patrickdundas merged commit 6ea934f into main Jul 29, 2026
5 of 6 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.

1 participant