mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-16 06:06:18 -08:00
fix(playlist): omit ambiguous portals for multi-MAC pastes, align scanner and candidate caps
- Several MACs meeting portal-shaped URLs on different hosts now yield MAC-only candidates: there is no deterministic owner for either portal, and prefilling half the accounts with the wrong panel only fails later at authentication. Same-host Real/Panel pairs and one portal shared by a MAC list stay unambiguous. - The URL scanner cap is raised to match the candidate cap (16), so a nine-link handout is no longer truncated to eight before assembly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JE1De2dfyRZMYh4H2iGXb4
This commit is contained in:
3 files changed
+48
-9
No files matched your search
@@ -678,6 +678,27 @@ describe('detectProviderImportCandidates', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('omits the portal when several MACs meet portals on different hosts', () => {
|
||||
// Two panels + two MACs in one paste: no deterministic owner for
|
||||
// either portal, so the candidates carry the MAC alone instead of
|
||||
// prefilling half of them with the wrong panel.
|
||||
const candidates = detectProviderImportCandidates(
|
||||
[
|
||||
'http://panel-a.example.com/c/',
|
||||
'MAC: 00:1A:79:AA:AA:AA',
|
||||
'http://panel-b.example.com/c/',
|
||||
'MAC: 00:1A:79:BB:BB:BB',
|
||||
].join('\n')
|
||||
);
|
||||
|
||||
const stalker = only(candidates, 'stalker');
|
||||
expect(stalker).toHaveLength(2);
|
||||
for (const candidate of stalker) {
|
||||
expect(candidate.portalUrl).toBeUndefined();
|
||||
expect(candidate.confidence).toBe('low');
|
||||
}
|
||||
});
|
||||
|
||||
it('surfaces every MAC of a long multi-account list', () => {
|
||||
const macs = Array.from(
|
||||
{ length: 6 },
|
||||
@@ -779,15 +800,18 @@ describe('detectProviderImportCandidates', () => {
|
||||
expect(only(candidates, 'm3u-url')).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('caps the number of returned candidates', () => {
|
||||
const urls = Array.from(
|
||||
it('surfaces every link of a long list and caps only pathological pastes', () => {
|
||||
const twelve = Array.from(
|
||||
{ length: 12 },
|
||||
(_, index) => `https://lists.example.com/list-${index}.m3u`
|
||||
).join('\n');
|
||||
expect(detectProviderImportCandidates(twelve)).toHaveLength(12);
|
||||
|
||||
expect(
|
||||
detectProviderImportCandidates(urls).length
|
||||
).toBeLessThanOrEqual(16);
|
||||
const twenty = Array.from(
|
||||
{ length: 20 },
|
||||
(_, index) => `https://lists.example.com/list-${index}.m3u`
|
||||
).join('\n');
|
||||
expect(detectProviderImportCandidates(twenty)).toHaveLength(16);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -115,7 +115,21 @@ export function detectProviderImportCandidates(
|
||||
// label belongs to — and a device ID submitted with the wrong MAC is
|
||||
// pinned by the portal permanently. Multi-MAC candidates therefore carry
|
||||
// portal + MAC only, and the user supplies identity per account.
|
||||
const portal = pickStalkerPortalUrl(urls, labeled);
|
||||
// Several MACs meeting portal-shaped URLs on DIFFERENT hosts is two
|
||||
// accounts from two panels in one paste — there is no deterministic way
|
||||
// to say which MAC belongs to which portal, so those candidates carry the
|
||||
// MAC alone instead of prefilling half of them with the wrong panel.
|
||||
// Same-host URL pairs (the Real/Panel lines of scanner dumps) stay
|
||||
// unambiguous, as does one portal shared by a whole MAC list.
|
||||
const stalkerHosts = new Set(
|
||||
urls
|
||||
.filter((url) => url.role === 'stalker')
|
||||
.map((url) => url.parsed.hostname)
|
||||
);
|
||||
const portalAmbiguous = macs.length > 1 && stalkerHosts.size > 1;
|
||||
const portal = portalAmbiguous
|
||||
? null
|
||||
: pickStalkerPortalUrl(urls, labeled);
|
||||
const identity: LabeledFields = macs.length === 1 ? labeled : {};
|
||||
for (const macAddress of macs) {
|
||||
candidates.push(
|
||||
|
||||
@@ -52,9 +52,10 @@ const HOSTISH_PATTERN = /^[a-z0-9][a-z0-9.-]*(?::\d{2,5})?$/i;
|
||||
|
||||
const WRAPPING_CHARS = /^["'`«<([]+|["'`»>)\]]+$/g;
|
||||
|
||||
const MAX_URLS = 8;
|
||||
// High enough that a real multi-account handout is never silently truncated;
|
||||
// only a pathological paste (hex dumps, logs) hits it.
|
||||
// Both caps guard against pathological pastes only, and stay aligned with
|
||||
// the assembler's candidate cap so a real multi-link or multi-account
|
||||
// handout is never truncated by the scanner before assembly even sees it.
|
||||
const MAX_URLS = 16;
|
||||
const MAX_MACS = 12;
|
||||
|
||||
interface FieldMatcher {
|
||||
|
||||
Reference in new issue
Block a user