121 lines
4.2 KiB
JavaScript
121 lines
4.2 KiB
JavaScript
const assert = require('node:assert/strict');
|
|
const { EventEmitter } = require('node:events');
|
|
const test = require('node:test');
|
|
const {
|
|
WATCHDOG_CHANNEL,
|
|
WATCHDOG_PATH,
|
|
isAuthorizedWatchdogEvent,
|
|
registerWatchdogHandler,
|
|
sendWatchdogReset
|
|
} = require('../js/watchdog.js');
|
|
|
|
function createHttpClient({ statusCode = 204, hang = false } = {}) {
|
|
const calls = [];
|
|
const httpClient = {
|
|
request(options, onResponse) {
|
|
const request = new EventEmitter();
|
|
request.destroy = (error) => request.emit('error', error);
|
|
request.end = (body) => {
|
|
calls.push({ options, body });
|
|
if (!hang) {
|
|
queueMicrotask(() => onResponse({ statusCode, resume() {} }));
|
|
}
|
|
};
|
|
return request;
|
|
}
|
|
};
|
|
return { httpClient, calls };
|
|
}
|
|
|
|
test('sends healthy true as a fixed local POST', async () => {
|
|
const { httpClient, calls } = createHttpClient();
|
|
|
|
await sendWatchdogReset({ healthy: true }, httpClient);
|
|
|
|
assert.deepEqual(calls, [{
|
|
options: {
|
|
hostname: 'localhost',
|
|
path: WATCHDOG_PATH,
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' }
|
|
},
|
|
body: '{"healthy":true}'
|
|
}]);
|
|
});
|
|
|
|
test('sends healthy false in the request body', async () => {
|
|
const { httpClient, calls } = createHttpClient();
|
|
|
|
await sendWatchdogReset({ healthy: false }, httpClient);
|
|
|
|
assert.equal(calls[0].body, '{"healthy":false}');
|
|
});
|
|
|
|
test('rejects malformed payloads without making a request', async () => {
|
|
const { httpClient, calls } = createHttpClient();
|
|
|
|
for (const payload of [null, [], {}, { healthy: 1 }, { healthy: true, url: 'http://example.test' }]) {
|
|
await assert.rejects(sendWatchdogReset(payload, httpClient), /boolean healthy field/);
|
|
}
|
|
|
|
assert.equal(calls.length, 0);
|
|
});
|
|
|
|
test('rejects non-success HTTP responses without parsing their body', async () => {
|
|
const { httpClient } = createHttpClient({ statusCode: 503 });
|
|
|
|
await assert.rejects(sendWatchdogReset({ healthy: true }, httpClient), /HTTP 503/);
|
|
});
|
|
|
|
test('rejects responses without a numeric HTTP status', async () => {
|
|
const { httpClient } = createHttpClient({ statusCode: null });
|
|
|
|
await assert.rejects(sendWatchdogReset({ healthy: true }, httpClient), /HTTP unknown/);
|
|
});
|
|
|
|
test('rejects requests that exceed the timeout', async () => {
|
|
const { httpClient } = createHttpClient({ hang: true });
|
|
|
|
await assert.rejects(sendWatchdogReset({ healthy: true }, httpClient, 5), /timed out after 5 ms/);
|
|
});
|
|
|
|
test('rejects unauthorized renderers without making a request', async () => {
|
|
let registeredChannel;
|
|
let handler;
|
|
const { httpClient, calls } = createHttpClient();
|
|
const mainFrame = { url: 'https://allowed.example/' };
|
|
const mainWindow = { isDestroyed: () => false, webContents: { mainFrame } };
|
|
const ipcMain = {
|
|
handle(channel, registeredHandler) {
|
|
registeredChannel = channel;
|
|
handler = registeredHandler;
|
|
}
|
|
};
|
|
|
|
registerWatchdogHandler(ipcMain, {
|
|
isAuthorized: (event) => isAuthorizedWatchdogEvent(event, mainWindow, (url) => url === mainFrame.url),
|
|
httpClient
|
|
});
|
|
|
|
assert.equal(registeredChannel, WATCHDOG_CHANNEL);
|
|
const otherRenderer = { sender: { mainFrame }, senderFrame: mainFrame };
|
|
await assert.rejects(handler(otherRenderer, { healthy: true }), /not authorized/);
|
|
assert.equal(calls.length, 0);
|
|
});
|
|
|
|
test('rejects subframes and renderers on disallowed URLs', () => {
|
|
const mainFrame = { url: 'https://allowed.example/' };
|
|
const mainWindow = { isDestroyed: () => false, webContents: { mainFrame } };
|
|
const isUrlAllowed = (url) => url === mainFrame.url;
|
|
const blockedFrame = { url: 'https://blocked.example/' };
|
|
const blockedWindow = { isDestroyed: () => false, webContents: { mainFrame: blockedFrame } };
|
|
|
|
assert.equal(isAuthorizedWatchdogEvent({
|
|
sender: mainWindow.webContents,
|
|
senderFrame: { url: mainFrame.url }
|
|
}, mainWindow, isUrlAllowed), false);
|
|
assert.equal(isAuthorizedWatchdogEvent({
|
|
sender: blockedWindow.webContents,
|
|
senderFrame: blockedFrame
|
|
}, blockedWindow, isUrlAllowed), false);
|
|
}); |