-
-
Notifications
You must be signed in to change notification settings - Fork 85
Feat: BitTorrent v2 Support [BEP 52] #193
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
leoherzog
wants to merge
19
commits into
webtorrent:master
Choose a base branch
from
leoherzog:patch-2
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+213
−35
Open
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
3289039
Add initial BitTorrent v2 support with dual hash validation
leoherzog 44fa7b5
Add Torrent v2 Tests
leoherzog c4353fc
Simplify Implementation and Add Option to Generate v1, v2, or Hybrid
leoherzog dbc9501
Rethink Hated Ifs
leoherzog 20374a9
Fix Redundant ArrayBuffer Checks
leoherzog f34b051
Assume v1, v2, or Hybrid Based on Input Structure
leoherzog 5577ce6
Check for Piece Layers
leoherzog 301c07b
Bugfix for Hybrid Validation
leoherzog f147872
Flatten the File Tree, but Don't Modify `torrent.info.files`
leoherzog 1ca7bec
Merge master into patch-2
claude 559f9f9
Merge v11.0.19 Upstream Changes
leoherzog 13c70e7
Simplify v1/v2/Hybrid Detection
leoherzog a7771c3
Extract flattenFileTree to Top-Level Function
leoherzog 2ad638f
Support BEP-47 File Attributes in flattenFileTree
leoherzog d9204a7
Don't Set pieces to Empty Array for v2 Torrents
leoherzog 434ad73
Add version Field
leoherzog dfb54c8
Assert infoHash and pieces Undefined for v2-only Torrents
leoherzog 38f7f43
Use Consistent Assertions and Verify Known Hashes
leoherzog 7903819
Add Hybrid Magnet Link Test
leoherzog File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| import fs from 'fs' | ||
| import parseTorrent from '../index.js' | ||
| import test from 'tape' | ||
|
|
||
| test('Test BitTorrent v2 hash support', async t => { | ||
| let parsed | ||
|
|
||
| // v2 info hash (as a hex string - 64 characters) | ||
| const v2Hash = 'a'.repeat(64) | ||
| parsed = await parseTorrent(v2Hash) | ||
| t.equal(parsed.infoHashV2, v2Hash.toLowerCase()) | ||
|
leoherzog marked this conversation as resolved.
|
||
| t.equal(parsed.infoHash, undefined, 'v2-only should not have v1 infoHash') | ||
| t.equal(parsed.name, undefined) | ||
| t.deepEqual(parsed.announce, []) | ||
|
|
||
| // v2 info hash (as a Buffer - 32 bytes) | ||
| const v2HashBuffer = Buffer.from(v2Hash, 'hex') | ||
| parsed = await parseTorrent(v2HashBuffer) | ||
| t.equal(parsed.infoHashV2, v2Hash.toLowerCase()) | ||
|
|
||
| // magnet uri with v2 hash (btmh) | ||
| const magnetV2 = `magnet:?xt=urn:btmh:1220${v2Hash}` | ||
| parsed = await parseTorrent(magnetV2) | ||
| t.equal(parsed.infoHashV2, v2Hash.toLowerCase(), 'magnet v2 hash should match') | ||
|
|
||
| // hybrid magnet uri (both btih and btmh) | ||
| const hybridMagnet = 'magnet:?xt=urn:btih:631a31dd0a46257d5078c0dee4e66e26f73e42ac&xt=urn:btmh:1220d8dd32ac93357c368556af3ac1d95c9d76bd0dff6fa9833ecdac3d53134efabb' | ||
| parsed = await parseTorrent(hybridMagnet) | ||
| t.equal(parsed.infoHash, '631a31dd0a46257d5078c0dee4e66e26f73e42ac', 'hybrid magnet should have v1 infoHash') | ||
| t.equal(parsed.infoHashV2, 'd8dd32ac93357c368556af3ac1d95c9d76bd0dff6fa9833ecdac3d53134efabb', 'hybrid magnet should have v2 infoHash') | ||
|
|
||
| // parsed torrent with both v1 and v2 hashes (hybrid) | ||
| const torrentObjHybrid = { | ||
| infoHash: 'd2474e86c95b19b8bcfdb92bc12c9d44667cfa36', | ||
| infoHashV2: v2Hash | ||
| } | ||
| parsed = await parseTorrent(torrentObjHybrid) | ||
| t.equal(parsed.infoHash, 'd2474e86c95b19b8bcfdb92bc12c9d44667cfa36') | ||
| t.equal(parsed.infoHashV2, v2Hash.toLowerCase()) | ||
|
|
||
| t.end() | ||
| }) | ||
|
leoherzog marked this conversation as resolved.
|
||
|
|
||
| test('Parse BitTorrent v2 torrent files', async t => { | ||
| const v2Buf = fs.readFileSync('./test/torrents/bittorrent-v2-test.torrent') | ||
| const hybridBuf = fs.readFileSync('./test/torrents/bittorrent-v2-hybrid-test.torrent') | ||
|
|
||
| // Test v2 torrent (should auto-detect and generate v2 hash) | ||
| const v2Parsed = await parseTorrent(v2Buf) | ||
| t.equal(v2Parsed.infoHashV2, 'caf1e1c30e81cb361b9ee167c4aa64228a7fa4fa9f6105232b28ad099f3a302e', 'v2 torrent should have correct v2 hash') | ||
| t.equal(v2Parsed.infoHash, undefined, 'v2-only torrent should not have v1 infoHash') | ||
| t.equal(v2Parsed.pieces, undefined, 'v2-only torrent should not have pieces') | ||
|
|
||
| // Test hybrid torrent (should auto-detect and generate both hashes) | ||
| const hybrid = await parseTorrent(hybridBuf) | ||
| t.equal(hybrid.infoHash, '631a31dd0a46257d5078c0dee4e66e26f73e42ac', 'Hybrid should have correct v1 hash') | ||
| t.equal(hybrid.infoHashV2, 'd8dd32ac93357c368556af3ac1d95c9d76bd0dff6fa9833ecdac3d53134efabb', 'Hybrid should have correct v2 hash') | ||
|
|
||
| // All should have standard properties | ||
| ;[v2Parsed, hybrid].forEach(parsed => { | ||
| t.ok(parsed.name, 'Should have name') | ||
| t.ok(Array.isArray(parsed.files), 'Should have files array') | ||
| t.ok(typeof parsed.length === 'number', 'Should have length') | ||
| }) | ||
|
|
||
| t.end() | ||
| }) | ||
|
|
||
| test('Test auto-detection behavior', async t => { | ||
| const torrentBuf = fs.readFileSync('./test/torrents/bittorrent-v2-test.torrent') | ||
|
|
||
| // Test that v2 torrent auto-detects and generates appropriate hashes | ||
| const parsed = await parseTorrent(torrentBuf) | ||
| t.equal(parsed.infoHashV2, 'caf1e1c30e81cb361b9ee167c4aa64228a7fa4fa9f6105232b28ad099f3a302e', 'v2 torrent should have correct auto-generated v2 hash') | ||
| t.equal(parsed.infoHash, undefined, 'v2-only should not have v1 infoHash') | ||
| t.equal(parsed.pieces, undefined, 'v2-only should not have pieces') | ||
|
|
||
|
leoherzog marked this conversation as resolved.
|
||
| t.end() | ||
| }) | ||
|
|
||
| test('Test validation requires either v1 or v2 hash', async t => { | ||
| // Test that magnet with no valid hash fails | ||
| try { | ||
| await parseTorrent('magnet:?xt=urn:invalid:123') | ||
| t.fail('Should have thrown error for invalid magnet') | ||
| } catch (err) { | ||
| t.ok(err instanceof Error) | ||
| t.ok(err.message.includes('Invalid torrent identifier')) | ||
| } | ||
|
|
||
| // Test that object with neither hash fails | ||
| try { | ||
| await parseTorrent({ name: 'test' }) | ||
| t.fail('Should have thrown error for object without hashes') | ||
| } catch (err) { | ||
| t.ok(err instanceof Error) | ||
| t.ok(err.message.includes('Invalid torrent identifier')) | ||
| } | ||
|
|
||
| t.end() | ||
| }) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
Binary file not shown.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.