Harden renderer startup readiness recovery

Require a bounded Ready signal after each main-document load, cancel the deadline on successful readiness or window disposal, and keep recovery limited to one reload before the branded failure surface.

Route renderer initialization failures through production startup handlers and reject malformed authenticated remote keyboard payloads without throwing or logging.
This commit is contained in:
Sucukdeluxe
2026-08-13 22:25:28 +02:00
parent d5ff45644c
commit a4d0854e76
4 changed files with 436 additions and 24 deletions
+76
View File
@@ -0,0 +1,76 @@
const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const vm = require('node:vm');
function loadRemoteInputHandler(sendInputEvent, debugLog = () => {}) {
const source = fs.readFileSync(path.join(__dirname, '..', 'main.js'), 'utf8');
const handlerStart = source.indexOf("ipcMain.on('remote:input-event'");
const handlerEnd = source.indexOf('\nfunction buildModifiers', handlerStart);
const modifiersEnd = source.indexOf('\n// IPC: Get capture source ID', handlerEnd);
assert.notEqual(handlerStart, -1);
assert.notEqual(handlerEnd, -1);
assert.notEqual(modifiersEnd, -1);
let inputHandler;
const mainWindow = {
isDestroyed: () => false,
getBounds: () => ({ x: 0, y: 0, width: 1100, height: 750 }),
getContentBounds: () => ({ x: 7, y: 30, width: 1086, height: 713 }),
webContents: { sendInputEvent }
};
const context = vm.createContext({
ipcMain: {
on(channel, handler) {
if (channel === 'remote:input-event') inputHandler = handler;
}
},
mainWindow,
configStore: {
load: () => ({ globalSettings: { remote: { allowInput: true } } })
},
debugLog,
process: { platform: 'win32' },
isFinite
});
vm.runInContext(source.slice(handlerStart, handlerEnd) + source.slice(handlerEnd, modifiersEnd), context);
assert.equal(typeof inputHandler, 'function');
return inputHandler;
}
test('authenticated keyboard input without a string key is discarded without throwing', () => {
const sent = [];
const logs = [];
const handler = loadRemoteInputHandler(event => sent.push(event), (...args) => logs.push(args));
const invalidPayloads = [
{ role: 'admin', type: 'keydown' },
{ role: 'admin', type: 'keydown', key: null },
{ role: 'admin', type: 'keydown', key: 1 },
{ role: 'admin', type: 'keydown', key: '' },
{ role: 'admin', type: 'keyup' },
{ role: 'admin', type: 'keyup', key: {} }
];
for (const payload of invalidPayloads) {
assert.doesNotThrow(() => handler({}, payload));
}
assert.deepEqual(sent, []);
assert.deepEqual(logs, []);
});
test('authenticated keyboard input with a string key keeps normal keydown and keyup behavior', () => {
const sent = [];
const handler = loadRemoteInputHandler(event => sent.push(event));
handler({}, { role: 'admin', type: 'keydown', key: 'a', ctrl: true });
handler({}, { role: 'admin', type: 'keyup', key: 'a', ctrl: true });
assert.deepEqual(JSON.parse(JSON.stringify(sent)), [
{ type: 'keyDown', keyCode: 'a', modifiers: ['control'] },
{ type: 'char', keyCode: 'a', modifiers: ['control'] },
{ type: 'keyUp', keyCode: 'a', modifiers: ['control'] }
]);
});