mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 16:02:26 +00:00
304 lines
9.8 KiB
JavaScript
304 lines
9.8 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
|
|
import { WSS_TRACKERS } from "../js/constants.js";
|
|
import {
|
|
normalizeAndAugmentMagnet as normalizeMagnetObject,
|
|
safeDecodeMagnet,
|
|
} from "../js/magnetUtils.js";
|
|
import {
|
|
buildMagnetUri,
|
|
extractMagnetHints,
|
|
normalizeMagnetInput,
|
|
} from "../js/magnetShared.js";
|
|
|
|
function getParamValues(magnet, key) {
|
|
const parsed = new URL(magnet);
|
|
return parsed.searchParams.getAll(key);
|
|
}
|
|
|
|
function assertDefaultTrackersPresent(magnet) {
|
|
const trackers = getParamValues(magnet, "tr");
|
|
for (const tracker of WSS_TRACKERS) {
|
|
assert.ok(
|
|
trackers.includes(tracker),
|
|
`Expected default tracker ${tracker} to be present`
|
|
);
|
|
}
|
|
}
|
|
|
|
test("safeDecodeMagnet handles encoded values", () => {
|
|
const rawMagnet =
|
|
"magnet:?xt=urn:btih:0123456789abcdef0123456789abcdef01234567&dn=Example";
|
|
const encodedMagnet = encodeURIComponent(rawMagnet);
|
|
assert.equal(
|
|
safeDecodeMagnet(encodedMagnet),
|
|
rawMagnet,
|
|
"Percent-encoded magnets should be decoded"
|
|
);
|
|
});
|
|
|
|
test("safeDecodeMagnet leaves plain strings untouched", () => {
|
|
const rawMagnet =
|
|
"magnet:?xt=urn:btih:abcdefabcdefabcdefabcdefabcdefabcdefabcd";
|
|
assert.equal(
|
|
safeDecodeMagnet(rawMagnet),
|
|
rawMagnet,
|
|
"Plain magnet strings should pass through"
|
|
);
|
|
});
|
|
|
|
test("bare hashes normalize consistently", () => {
|
|
const infoHash = "0123456789abcdef0123456789abcdef01234567";
|
|
const objectResult = normalizeMagnetObject(infoHash);
|
|
|
|
assert.ok(objectResult.didChange, "Bare hashes should mark didChange true");
|
|
|
|
const xtValues = getParamValues(objectResult.magnet, "xt");
|
|
assert.deepEqual(xtValues, [`urn:btih:${infoHash}`]);
|
|
assertDefaultTrackersPresent(objectResult.magnet);
|
|
});
|
|
|
|
test("legacy %3A payloads decode", () => {
|
|
const infoHash = "abcdefabcdefabcdefabcdefabcdefabcdefabcd";
|
|
const encoded = `magnet:?xt=urn%3Abtih%3A${infoHash}&dn=Example`;
|
|
const objectResult = normalizeMagnetObject(encoded);
|
|
|
|
const xtValues = getParamValues(objectResult.magnet, "xt");
|
|
assert.deepEqual(xtValues, [`urn:btih:${infoHash}`]);
|
|
});
|
|
|
|
test("duplicate trackers and hints stay in sync", () => {
|
|
const infoHash = "fedcba9876543210fedcba9876543210fedcba98";
|
|
const baseMagnet =
|
|
`magnet:?xt=urn:btih:${infoHash}` +
|
|
"&tr=wss://tracker.openwebtorrent.com" +
|
|
"&tr=WsS://tracker.openwebtorrent.com/";
|
|
|
|
const objectResult = normalizeMagnetObject(baseMagnet, {
|
|
extraTrackers: [
|
|
"http://tracker.invalid",
|
|
"wss://tracker.openwebtorrent.com",
|
|
],
|
|
xs: "https://cdn.example.com/video.torrent",
|
|
webSeed: "https://cdn.example.com/files/",
|
|
});
|
|
|
|
const trackers = getParamValues(objectResult.magnet, "tr");
|
|
const openwebCount = trackers.filter(
|
|
(value) => value === "wss://tracker.openwebtorrent.com"
|
|
).length;
|
|
assert.equal(openwebCount, 1, "Duplicate trackers should be deduped when appended");
|
|
assert.ok(
|
|
!trackers.includes("http://tracker.invalid"),
|
|
"HTTP tracker candidates should be ignored"
|
|
);
|
|
|
|
const webSeeds = getParamValues(objectResult.magnet, "ws");
|
|
assert.deepEqual(webSeeds, ["https://cdn.example.com/files/"]);
|
|
|
|
const xsValues = getParamValues(objectResult.magnet, "xs");
|
|
assert.deepEqual(xsValues, ["https://cdn.example.com/video.torrent"]);
|
|
});
|
|
|
|
test("object helper enforces HTTPS web seeds when on HTTPS", () => {
|
|
const infoHash = "0123456789abcdef0123456789abcdef01234567";
|
|
const messages = [];
|
|
const result = normalizeMagnetObject(`magnet:?xt=urn:btih:${infoHash}`, {
|
|
webSeed: [
|
|
"https://cdn.example.com/video.mp4",
|
|
"http://cdn.example.com/legacy.mp4",
|
|
],
|
|
logger: (msg) => messages.push(msg),
|
|
appProtocol: "https:",
|
|
});
|
|
|
|
const seeds = getParamValues(result.magnet, "ws");
|
|
assert.deepEqual(seeds, ["https://cdn.example.com/video.mp4"]);
|
|
assert.equal(messages.length, 1, "HTTP web seeds should trigger a log message");
|
|
assert.ok(
|
|
messages[0].includes("Skipping insecure web seed"),
|
|
"Expected skip log for HTTP seed"
|
|
);
|
|
});
|
|
|
|
test("object helper allows HTTP seeds on HTTP origins", () => {
|
|
const infoHash = "abcdefabcdefabcdefabcdefabcdefabcdefabcd";
|
|
const result = normalizeMagnetObject(`magnet:?xt=urn:btih:${infoHash}`, {
|
|
webSeed: "http://cdn.example.com/video.mp4",
|
|
appProtocol: "http:",
|
|
});
|
|
|
|
const seeds = getParamValues(result.magnet, "ws");
|
|
assert.deepEqual(seeds, ["http://cdn.example.com/video.mp4"]);
|
|
});
|
|
|
|
test("extractMagnetHints returns first ws/xs pair", () => {
|
|
const magnet =
|
|
"magnet:?xt=urn:btih:abcdef0123456789abcdef0123456789abcdef01" +
|
|
"&ws=https://cdn.example.com/base/" +
|
|
"&ws=https://cdn.example.com/duplicate/" +
|
|
"&xs=https://cdn.example.com/video.torrent";
|
|
|
|
const hints = extractMagnetHints(magnet);
|
|
assert.deepEqual(hints, {
|
|
ws: "https://cdn.example.com/base/",
|
|
xs: "https://cdn.example.com/video.torrent",
|
|
});
|
|
});
|
|
|
|
test("object helper reports didChange when output differs", () => {
|
|
const infoHash = "abcdef0123456789abcdef0123456789abcdef01";
|
|
const result = normalizeMagnetObject(`magnet:?xt=urn:btih:${infoHash}`, {
|
|
webSeed: "https://cdn.example.com/video.mp4",
|
|
});
|
|
assert.ok(result.didChange, "Augmenting with web seeds should mark didChange");
|
|
});
|
|
|
|
test("helpers trim fragments from non-magnet values", () => {
|
|
const url = "https://example.com/video.mp4#fragment";
|
|
const objectResult = normalizeMagnetObject(url);
|
|
assert.equal(objectResult.magnet, "https://example.com/video.mp4");
|
|
assert.ok(
|
|
objectResult.didChange,
|
|
"Dropping the fragment should be reflected in didChange"
|
|
);
|
|
});
|
|
|
|
test("normalizeAndAugmentMagnet filters out known broken trackers", () => {
|
|
const infoHash = "abcdef0123456789abcdef0123456789abcdef01";
|
|
const brokenTrackers = [
|
|
"wss://tracker.dler.org/announce",
|
|
"wss://tracker.ghostchu-services.top/announce"
|
|
];
|
|
|
|
const rawMagnet =
|
|
`magnet:?xt=urn:btih:${infoHash}` +
|
|
`&tr=${brokenTrackers[0]}` +
|
|
`&tr=${brokenTrackers[1]}`;
|
|
|
|
const result = normalizeMagnetObject(rawMagnet);
|
|
|
|
const trackers = getParamValues(result.magnet, "tr");
|
|
for (const broken of brokenTrackers) {
|
|
assert.ok(
|
|
!trackers.includes(broken),
|
|
`Expected broken tracker ${broken} to be removed`
|
|
);
|
|
}
|
|
|
|
assertDefaultTrackersPresent(result.magnet);
|
|
});
|
|
|
|
test("normalizeMagnetInput parses each inbound parameter exactly once", () => {
|
|
const infoHash = "0123456789abcdef0123456789abcdef01234567";
|
|
const rawMagnet =
|
|
`magnet:?xt=urn:btih:${infoHash}` +
|
|
"&tr=wss://tracker.example.com/announce" +
|
|
"&ws=https://cdn.example.com/files/" +
|
|
"&xs=https://cdn.example.com/file.torrent";
|
|
|
|
const normalized = normalizeMagnetInput(rawMagnet);
|
|
|
|
assert.equal(normalized.params.length, 4, "Expected one parsed entry per inbound param");
|
|
assert.deepEqual(
|
|
normalized.params.map((param) => param.lowerKey),
|
|
["xt", "tr", "ws", "xs"],
|
|
"Parameter parsing order should match inbound order"
|
|
);
|
|
|
|
const rebuilt = buildMagnetUri(
|
|
normalized.normalizedScheme,
|
|
normalized.params,
|
|
normalized.fragment
|
|
);
|
|
assert.equal(
|
|
rebuilt,
|
|
rawMagnet,
|
|
"Rebuilding unchanged parsed params should not introduce duplicates"
|
|
);
|
|
});
|
|
|
|
test("normalizeAndAugmentMagnet keeps unchanged xt/tr/ws/xs params singular", () => {
|
|
const infoHash = "fedcba9876543210fedcba9876543210fedcba98";
|
|
const inboundTracker = "wss://tracker.example.com/announce";
|
|
const inboundWebSeed = "https://cdn.example.com/files/";
|
|
const inboundXs = "https://cdn.example.com/file.torrent";
|
|
const rawMagnet =
|
|
`magnet:?xt=urn:btih:${infoHash}` +
|
|
`&tr=${inboundTracker}` +
|
|
`&ws=${inboundWebSeed}` +
|
|
`&xs=${inboundXs}`;
|
|
|
|
const result = normalizeMagnetObject(rawMagnet);
|
|
|
|
const xtValues = getParamValues(result.magnet, "xt");
|
|
const trackers = getParamValues(result.magnet, "tr");
|
|
const webSeeds = getParamValues(result.magnet, "ws");
|
|
const xsValues = getParamValues(result.magnet, "xs");
|
|
|
|
assert.equal(xtValues.length, 1, "xt should remain singular");
|
|
assert.equal(
|
|
trackers.filter((value) => value === inboundTracker).length,
|
|
1,
|
|
"Inbound tracker should remain singular"
|
|
);
|
|
assert.equal(
|
|
webSeeds.filter((value) => value === inboundWebSeed).length,
|
|
1,
|
|
"Inbound web seed should remain singular"
|
|
);
|
|
assert.equal(
|
|
xsValues.filter((value) => value === inboundXs).length,
|
|
1,
|
|
"Inbound xs hint should remain singular"
|
|
);
|
|
});
|
|
|
|
test("normalizeMagnetInput preserves parameter values containing additional equals signs", () => {
|
|
const infoHash = "0123456789abcdef0123456789abcdef01234567";
|
|
const rawMagnet =
|
|
`magnet:?xt=urn:btih:${infoHash}` +
|
|
"&ws=https://cdn.example.com/video.mp4%3FX-Amz-Signature=abc123==%26X-Amz-Credential=test%3Dvalue" +
|
|
"&xs=https://cdn.example.com/video.torrent%3Ftoken=ZXlKaGJHY2lPaUpJVXpJMU5pSjkuZXlKcFpDST0=%26policy=a%3Db" +
|
|
"&dn=Episode=01=Directors=Cut" +
|
|
"&foo=bar=baz==";
|
|
|
|
const normalized = normalizeMagnetInput(rawMagnet);
|
|
const valuesByKey = Object.fromEntries(
|
|
normalized.params.map((param) => [param.lowerKey, param.value])
|
|
);
|
|
|
|
assert.equal(
|
|
valuesByKey.ws,
|
|
"https://cdn.example.com/video.mp4%3FX-Amz-Signature=abc123==%26X-Amz-Credential=test%3Dvalue",
|
|
"ws should keep the full signed URL token"
|
|
);
|
|
assert.equal(
|
|
valuesByKey.xs,
|
|
"https://cdn.example.com/video.torrent%3Ftoken=ZXlKaGJHY2lPaUpJVXpJMU5pSjkuZXlKcFpDST0=%26policy=a%3Db",
|
|
"xs should keep base64-like payloads and nested query params intact"
|
|
);
|
|
assert.equal(
|
|
valuesByKey.dn,
|
|
"Episode=01=Directors=Cut",
|
|
"dn should preserve all '=' characters"
|
|
);
|
|
assert.equal(
|
|
valuesByKey.foo,
|
|
"bar=baz==",
|
|
"Unknown params should preserve all '=' characters"
|
|
);
|
|
|
|
const rebuilt = buildMagnetUri(
|
|
normalized.normalizedScheme,
|
|
normalized.params,
|
|
normalized.fragment
|
|
);
|
|
assert.equal(
|
|
rebuilt,
|
|
rawMagnet,
|
|
"buildMagnetUri should reproduce multi-equals values verbatim"
|
|
);
|
|
});
|