Skip to content

fix(torrents): keep downloaded info hash in sync with the tracker - #51

Merged
florianjs merged 1 commit into
mainfrom
fix/issue-49-announce
Oct 8, 2026
Merged

florianjs merged 1 commit into
mainfrom
fix/issue-49-announce

Conversation

@florianjs

@florianjs florianjs commented Oct 8, 2026 •

Copy link
Copy Markdown
Owner

Summary

Fixes the two problems reported in #49.

1. "Tracker error: Torrent not found or inactive"

On download, the site and the Torznab download set info.private = 1. The info hash is the SHA-1 of the info dict, so for any torrent uploaded without the private flag, the downloaded file had a different hash from the one stored in the DB. The client then announced an unknown hash and got this error.

  • Upload: the .torrent is normalized when stored (private = 1, announce URLs removed). The DB stores the hash of that file, which is exactly the one clients will announce.
  • Download: the info dict is no longer modified (site, Torznab and the debug endpoint).
  • Upload message: it now tells the uploader to seed the .torrent served by the site. If the private flag had to be added, the hash differs from their local file.

2. Torrents pointing to localhost

runtimeConfig.public.trackerHttpUrl is evaluated at build time. install.sh ran a plain docker build without build args, so http://localhost:8080/announce was baked into the image. The runtime env TRACKER_HTTP_URL was ignored, because Nuxt only reads NUXT_PUBLIC_* at runtime.

  • docker-compose.prod.yml and docker-compose.local.yml now set NUXT_PUBLIC_TRACKER_{HTTP,UDP,WS}_URL from .env. Existing installs only need docker compose up -d, no rebuild.
  • install.sh now builds through docker compose build app, so the .env URLs are passed as build args.

Notes

  • Torrents already stored without the private flag keep their original hash. They now download and announce correctly, but are served as-is (non-private). Re-uploading them makes them private.
  • Uploaders whose torrent was not private must re-download the .torrent from the site to seed it.

Test plan

  • npx vitest run: 110 passing, including new normalizeTorrent tests (public torrent → private, stored hash = hash of the served file)
  • docker compose config passes for prod; bash -n scripts/install.sh
  • On staging, upload a non-private .torrent, download it from the site, and confirm the announce succeeds
  • On an existing install, run docker compose up -d and confirm the downloaded .torrent uses the real tracker domain

Closes #49

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Uploaded torrents are saved as private torrents without existing announce details. If this changes a torrent’s info hash, upload instructions explain that you’ll need to download the site’s torrent file to seed it.
    • Upload instructions also explain how to seed torrents that were already private.
  • Bug Fixes
    • Invalid torrent files are rejected with an error.
    • Downloaded torrents retain their original privacy setting while their announce details are personalized for your passkey.

Downloads forced info.private = 1, which changes the info hash whenever the
uploaded torrent was not private: clients then announced a hash the tracker
did not know and got "Torrent not found or inactive".

- make uploads private when stored and save the hash of the stored file
- never modify the info dict on download (site and Torznab)
- tell uploaders to seed the .torrent served by the site
- override public tracker URLs at runtime (NUXT_PUBLIC_TRACKER_*) and build
  the image through compose so .env URLs are used instead of localhost

Closes #49

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 9a392efb-670d-41c6-8cfe-6d6d8b2f58f8
📥 Commits

Reviewing files that changed from the base of the PR and between c1eac5f and 37787e9.

📒 Files selected for processing (9)
  • docker-compose.local.yml
  • docker-compose.prod.yml
  • scripts/install.sh
  • server/api/debug/torrent/[hash].get.ts
  • server/api/torrents/[hash]/download.get.ts
  • server/api/torrents/index.post.ts
  • server/api/torznab/download.get.ts
  • server/utils/torrentFile.ts
  • tests/security/torrent-file.test.ts
💤 Files with no reviewable changes (1)
  • server/api/debug/torrent/[hash].get.ts

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 1 remain after this review.


📝 Walkthrough

Walkthrough

The installer and Compose files now configure tracker URLs for the app service. Torrent uploads are normalized as private torrents without announce URLs, and personalized download endpoints leave the info dictionary unchanged.

Changes

Tracker URL configuration

Layer / File(s) Summary
Compose tracker URL configuration
docker-compose.local.yml, docker-compose.prod.yml, scripts/install.sh
The Compose files set runtime tracker URL variables. The installer builds the app service through Compose.

Torrent normalization

Layer / File(s) Summary
Torrent normalization contract and tests
server/utils/torrentFile.ts, tests/security/torrent-file.test.ts
normalizeTorrent returns normalized torrent bytes, the normalized info hash, and whether it added the private flag. Tests cover private and public torrents, removed announce data, and missing info dictionaries.
Upload normalization and response
server/api/torrents/index.post.ts
The upload endpoint stores normalized bytes and uses the normalized info hash. Its response includes seeding instructions and madePrivate.
Personalized torrent downloads
server/api/debug/torrent/[hash].get.ts, server/api/torrents/[hash]/download.get.ts, server/api/torznab/download.get.ts
These endpoints no longer change the info dictionary’s private flag while personalizing announce URLs.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: Medium

Sequence Diagram(s)

sequenceDiagram
  participant Uploader
  participant TorrentUploadEndpoint
  participant normalizeTorrent
  participant TorrentDatabase
  Uploader->>TorrentUploadEndpoint: Upload torrent
  TorrentUploadEndpoint->>normalizeTorrent: Normalize torrent bytes
  normalizeTorrent-->>TorrentUploadEndpoint: Return bytes, info hash, madePrivate
  TorrentUploadEndpoint->>TorrentDatabase: Store normalized bytes and info hash
  TorrentUploadEndpoint-->>Uploader: Return upload response and seeding guidance
Loading

Merge Risk: ⚪ Minimal · up to 37787

No actionable issue remains identified; the change is mergeable after normal checks.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The changes in server/utils/torrentFile.ts, the torrent upload and download endpoints, the debug endpoint, and tests/security/torrent-file.test.ts change private-flag normalization, announce-list … Move the torrent normalization, hash, endpoint, and related test changes to a separate pull request, or link an active issue that requires them. Keep the localhost URL configuration changes for issue #49.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 6 files. (2 skipped: 2… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the primary torrent change: keeping downloaded info hashes aligned with the tracker. It is concise and directly related to the changeset.
Linked Issues check ✅ Passed Issue #49 reports that installed torrents use localhost URLs. The production Compose file maps TRACKER_HTTP_URL, TRACKER_UDP_URL, and TRACKER_WS_URL to the runtime NUXT_PUBLIC_* variables. The…
Full details: Out of Scope Changes check

Explanation

The changes in server/utils/torrentFile.ts, the torrent upload and download endpoints, the debug endpoint, and tests/security/torrent-file.test.ts change private-flag normalization, announce-list handling, and stored info hashes. Issue #49 only concerns torrents pointing to localhost. The issue contains no requirement for torrent hash synchronization or private-torrent normalization. These changes have no demonstrated connection to the linked issue.

Full details: Docstring Coverage

Explanation

Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 6 files. (2 skipped: 2 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@florianjs
florianjs merged commit 3e7f4c9 into main Oct 8, 2026
1 check 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.

[QUESTION] torrents pointing to localhost

1 participant