Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion chrome/background/MpvBackend.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ const NativeHostName = 'com.faststream.mpv';
// An answer with a lower version, or none (a host from before 2026-10-04), is an
// outdated host: the stream still goes to it, and the toolbar button, the player's mpv
// button and "Test mpv connection" say to install the host again.
export const RequiredHostVersion = 7;
export const RequiredHostVersion = 8;

// The largest message the host reads (MaxMessageBytes in native-host/faststream-mpv-host.mjs),
// as Firefox sends it: the JSON in UTF-8. A bigger one was never read: the host quit
Expand Down
26 changes: 16 additions & 10 deletions native-host/faststream-mpv-host.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
// install.ps1 (what it installs is part of the host a PC has), together with
// RequiredHostVersion and the hashes in tests/unit/mpvHostVersion.test.mjs, which fails
// until they agree.
export const HostVersion = 7;
export const HostVersion = 8;

// No mpv path from the environment (FASTSTREAM_MPV_PATH until 2026-10-04): config.json's
// mpvPath and the options page's path name one, and an environment variable reached
Expand Down Expand Up @@ -1638,18 +1638,20 @@ export function launchDirect(mpvPath, args) {
});
}

async function main() {
/**
* Answers the one message the extension sends this run (a watch: for as long as its port
* stays open). It only returns; main() ends the process.
*/
async function handleMessage() {
const config = readConfig();
const message = await readMessage();
if (message === TooLarge) {
debugLog(config, 'too-large', {});
await sendMessage({ok: false, error: 'the message was too large for the mpv host'});
process.exit(0);
return;
}
debugLog(config, 'received', loggedMessage(message));
if (!message || typeof message !== 'object') {
process.exit(0);
return;
}

Expand All @@ -1661,7 +1663,6 @@ async function main() {
} else {
await sendMessage({ok: true, mpv: false});
}
process.exit(0);
return;
}

Expand All @@ -1671,7 +1672,6 @@ async function main() {
const status = await queryDecoder(message.waitMs);
debugLog(config, 'status', status);
await sendMessage({ok: true, ...status});
process.exit(0);
return;
}

Expand All @@ -1687,31 +1687,37 @@ async function main() {
await watch.done;
// The last message ('closed') out before the host goes.
await sendMessage({type: 'bye'});
process.exit(0);
return;
}

if (message.type === 'open' && typeof message.url === 'string' && message.url.length > 0) {
if (!isStreamUrl(message.url)) {
debugLog(config, 'refused', {url: message.url});
await sendMessage({ok: false, error: 'mpv is only given http(s) streams'});
process.exit(0);
return;
}
const mpvPath = resolveMpvPath(message.mpvPath);
if (!mpvPath) {
await sendMessage({ok: false, error: mpvNotFoundError(message.mpvPath)});
process.exit(0);
return;
}
const result = await launchMpv(mpvPath, message, config);
debugLog(config, 'launched', {mpvPath, url: message.url, result});
await sendMessage(result);
process.exit(0);
return;
}

await sendMessage({ok: false, error: 'unknown message'});
}

/**
* The host: one message, then it ends - in this one place, after whatever the message
* asked for. With an exit in each branch, CodeQL read the checks before them as input
* deciding a sensitive action (js/user-controlled-bypass, #111 and #183): process.exit
* is one to it, and the "check" was whether an mpv exists.
*/
async function main() {
await handleMessage();
process.exit(0);
}

Expand Down
4 changes: 2 additions & 2 deletions tests/unit/mpvHostVersion.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ const installerFile = path.join(root, 'native-host/install.ps1');
// chrome/background/MpvBackend.mjs by one, then put the new values here (a failure prints
// the hashes).
const RECORDED = {
version: 7,
host: '7777800746d182f667a6177581c1e6ef48a3e72ae16c9d1b977d8829888bf769',
version: 8,
host: '3c0dcc5a3c2c2a0280e3771475aec468773c0eb4334c720101ec0433a2470945',
installer: 'db3b8027b508556b8af66eb4b8188460c2a5a6e1feb32d32b490f2e234b29b3a',
};

Expand Down
Loading