Skip to content

feat(tracker-adapters): add TBDev adapter and DocsPedia registry entry - #8

Merged
patrickdundas merged 1 commit into
mainfrom
feat/tbdev-adapter
Aug 9, 2026
Merged

feat(tracker-adapters): add TBDev adapter and DocsPedia registry entry#8
patrickdundas merged 1 commit into
mainfrom
feat/tbdev-adapter

Conversation

@patrickdundas

Copy link
Copy Markdown
Owner

Adds platformType: "tbdev" plus a DocsPedia registry entry.

Why a scraper

TBDev is the classic PHP tracker codebase with no API. Fingerprinted from the live site rather than assumed: X-Powered-By: PHP/7.4.33, /login.php, and Powered by TBDev in the footer (XBT tracker backend).

Cookie auth is forced, not chosen

TBDev's login form carries a CAPTCHA, so the login-and-collect-Set-Cookie flow the TorrentLeech adapter uses cannot work. The session cookies are long-lived, so capturing them once from a browser is the practical way in.

The uid is derived from whichever cookie name ends in uid — the prefix is site-specific (doccook_uid on DocsPedia, uid on stock TBDev). The match is anchored (/(^|_)uid$/) so it does not grab neighbouring cookies like doccook_hashv.

Byte units are binary despite decimal labels

TBDev's mksize() divides by 1024 at every step but labels the result kB/MB/GB/TB, so a TBDev 1.00 GB is one GiB. Routing that through parseBytes unchanged would read it against the decimal table and under-report by ~7% at GB and ~10% at TB. parseBytes is also case-sensitive with no kB entry, so the form TBDev actually emits would have thrown outright.

hitAndRuns is null, not 0

Stock TBDev has no hit-and-run accounting — there is no counter on the page. 0 would assert a clean record the tracker cannot vouch for.

Verification

16 unit tests against a fixture trimmed from a real /userdetails.php response, plus an end-to-end run against a live account: HTTP 200, username / class / karma parsed correctly, byte fields zero (new account, nothing seeded yet).

The GB-is-really-GiB mapping is reasoned from TBDev's source rather than measured, since every byte field on the test account is currently 0.00 kB — worth re-checking once real transfer numbers exist.

TBDev (tbdev.org) is the classic PHP tracker codebase and exposes no API, so
stats are scraped from the logged-in /userdetails.php page.

Auth is by session cookie rather than username/password, and that is forced
rather than chosen: TBDev's login form carries a CAPTCHA, so the login-and-
collect-Set-Cookie flow the TorrentLeech adapter uses cannot work. The cookies
are long-lived, so capturing them once from a browser is the practical way in.
The uid is derived from whichever cookie name ends in `uid`, since the prefix is
site-specific (DocsPedia uses doccook_uid, stock TBDev uses uid).

Byte units get their own parser. TBDev's mksize() divides by 1024 at every step
but labels the result kB/MB/GB/TB, so a TBDev "1.00 GB" is one GiB. Routing that
through parseBytes unchanged would read it against the decimal table and
under-report by ~7% at GB and ~10% at TB - and parseBytes has no lowercase "kB"
entry at all, so the form TBDev actually emits would have thrown.

hitAndRuns is null, not 0: stock TBDev has no hit-and-run accounting, and 0
would assert a clean record the tracker cannot vouch for.

Verified end-to-end against a live DocsPedia account: HTTP 200, username, class
and karma parsed correctly.
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

Knip Code Analysis

Found 9 total issues

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

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

⚠️ Tracker registry warnings

DocsPedia (`docspedia`) — 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

github-actions Bot commented Aug 9, 2026

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 f0e0d86 into main Aug 9, 2026
6 checks passed
@patrickdundas
patrickdundas deleted the feat/tbdev-adapter branch August 9, 2026 04:24
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