mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-09 17:36:15 -08:00
fix(pwa): sanitize portal URL before appending stalker cmd
A registered portal URL carrying a fragment would swallow the appended cmd (everything after # is never transmitted), and a trailing bare '?' produced '??cmd='. Drop the hash and pick the separator from the sanitized href before appending. Flagged by Greptile/Codex on #1334. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3326f73388
commit
e0617e1642
2 files changed
+52
-3
No files matched your search
@@ -440,6 +440,44 @@ https://stream.example/live.m3u8`);
|
||||
);
|
||||
});
|
||||
|
||||
it('keeps cmd in the query when the registered portal URL carries a fragment or bare ?', async () => {
|
||||
const httpClient = new StubHttpClient();
|
||||
httpClient.queueResponse({ js: { cmd: 'http://cdn/a.m3u8' } });
|
||||
httpClient.queueResponse({ js: { cmd: 'http://cdn/b.m3u8' } });
|
||||
|
||||
await withServer(
|
||||
createWebBackendApp({
|
||||
httpClient,
|
||||
resolveHostname: resolvePublicHost,
|
||||
}),
|
||||
async (baseUrl) => {
|
||||
// A fragment on the registered URL must not swallow the
|
||||
// appended cmd (fragments are never sent to the portal).
|
||||
const fragmentTarget = await registerProviderTarget(
|
||||
baseUrl,
|
||||
'http://stalker.example/portal.php#legacy'
|
||||
);
|
||||
await fetch(
|
||||
`${baseUrl}/stalker?targetId=${fragmentTarget}&action=create_link&cmd=${encodeURIComponent('/media/1.mpg')}`
|
||||
);
|
||||
|
||||
// A trailing bare '?' must not produce '??cmd='.
|
||||
const bareQueryTarget = await registerProviderTarget(
|
||||
baseUrl,
|
||||
'http://stalker.example/load.php?'
|
||||
);
|
||||
await fetch(
|
||||
`${baseUrl}/stalker?targetId=${bareQueryTarget}&action=create_link&cmd=${encodeURIComponent('/media/2.mpg')}`
|
||||
);
|
||||
|
||||
expect(httpClient.requests.map((request) => request.url)).toEqual([
|
||||
'http://stalker.example/portal.php?cmd=/media/1.mpg',
|
||||
'http://stalker.example/load.php?cmd=/media/2.mpg',
|
||||
]);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('normalizes provider errors for portal proxy calls', async () => {
|
||||
const httpClient = new StubHttpClient();
|
||||
httpClient.queueFailure(403, 'Forbidden');
|
||||
|
||||
@@ -233,10 +233,21 @@ export function createWebBackendApp(
|
||||
// serializer would fully percent-encode it, diverging from what a
|
||||
// real STB (and the Electron transport) sends. Append it to the
|
||||
// URL with the shared encoder and let axios serialize the rest.
|
||||
// The fragment is dropped first: a registered URL carrying `#...`
|
||||
// would otherwise swallow the appended cmd, and a trailing bare
|
||||
// `?` must not become `??cmd=`.
|
||||
const { cmd, ...proxyParams } = getProxyParams(req, ['targetId']);
|
||||
const requestUrl = cmd
|
||||
? `${url.href}${url.search ? '&' : '?'}cmd=${encodeStalkerCmdValue(cmd)}`
|
||||
: url.href;
|
||||
const portalUrl = new URL(url.href);
|
||||
portalUrl.hash = '';
|
||||
let requestUrl = portalUrl.href;
|
||||
if (cmd) {
|
||||
const separator = requestUrl.endsWith('?')
|
||||
? ''
|
||||
: portalUrl.search
|
||||
? '&'
|
||||
: '?';
|
||||
requestUrl = `${requestUrl}${separator}cmd=${encodeStalkerCmdValue(cmd)}`;
|
||||
}
|
||||
|
||||
// Provider URLs are validated by /provider-targets before they enter the registry.
|
||||
// codeql[js/request-forgery]
|
||||
|
||||
Reference in new issue
Block a user