fix: harden Electron security (theme injection, update window, navigation)

This commit is contained in:
2026-04-10 13:20:08 -07:00
parent 74bbace3fa
commit b76ac46cc0
2 changed files with 881 additions and 881 deletions
+11 -5
View File
@@ -418,9 +418,6 @@ async function launchApp(): Promise<void> {
win.loadURL('https://krunker.io'); win.loadURL('https://krunker.io');
} }
event.preventDefault(); event.preventDefault();
} else if (matchesKeybind(input, binds.pauseChat)) {
win.webContents.send('toggle-chat-pause');
event.preventDefault();
} else if (matchesKeybind(input, binds.fullscreenToggle)) { } else if (matchesKeybind(input, binds.fullscreenToggle)) {
win.setFullScreen(!win.isFullScreen()); win.setFullScreen(!win.isFullScreen());
event.preventDefault(); event.preventDefault();
@@ -470,6 +467,13 @@ async function launchApp(): Promise<void> {
// Intercept in-page navigation (e.g. window.location = '/social.html') // Intercept in-page navigation (e.g. window.location = '/social.html')
win.webContents.on('will-navigate', (event, url) => { win.webContents.on('will-navigate', (event, url) => {
try {
const parsed = new URL(url);
if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {
event.preventDefault();
return;
}
} catch { event.preventDefault(); return; }
if (url.includes('krunker.io') && !isGameURL(url)) { if (url.includes('krunker.io') && !isGameURL(url)) {
event.preventDefault(); event.preventDefault();
tabManager.openTab(url); tabManager.openTab(url);
@@ -521,11 +525,13 @@ async function launchApp(): Promise<void> {
const themeCSS = getThemeCSS(themeId, swapDir); const themeCSS = getThemeCSS(themeId, swapDir);
electronLog.log(`[KCC] CSS theme: id=${themeId}, css=${themeCSS ? themeCSS.length + ' chars' : 'none'}`); electronLog.log(`[KCC] CSS theme: id=${themeId}, css=${themeCSS ? themeCSS.length + ' chars' : 'none'}`);
if (themeCSS) { if (themeCSS) {
const escaped = themeCSS.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$/g, '\\$'); // Use <style> tag via executeJavaScript so @import rules work (insertCSS doesn't support them).
// Encode as base64 to avoid any escaping issues with template literals.
const b64 = Buffer.from(themeCSS).toString('base64');
win.webContents.executeJavaScript(`(() => { win.webContents.executeJavaScript(`(() => {
const s = document.createElement('style'); const s = document.createElement('style');
s.id = 'kcc-user-theme'; s.id = 'kcc-user-theme';
s.textContent = \`${escaped}\`; s.textContent = atob('${b64}');
document.head.appendChild(s); document.head.appendChild(s);
})()`).catch((err) => electronLog.warn('[KCC] Theme inject failed:', err)); })()`).catch((err) => electronLog.warn('[KCC] Theme inject failed:', err));
} }
+9 -15
View File
@@ -51,17 +51,6 @@ const UPDATE_HTML = `<!DOCTYPE html>
<div class="progress-container"> <div class="progress-container">
<div class="progress-bar" id="progressBar"></div> <div class="progress-bar" id="progressBar"></div>
</div> </div>
<script>
const { ipcRenderer } = require('electron');
const statusEl = document.getElementById('status');
const progressBar = document.getElementById('progressBar');
ipcRenderer.on('update-progress', function(event, message, percent) {
statusEl.textContent = message;
if (typeof percent === 'number') {
progressBar.style.width = percent + '%';
}
});
</script>
</body> </body>
</html>`; </html>`;
@@ -77,9 +66,9 @@ export function showUpdateWindow(): { window: BrowserWindow; sendProgress: (mess
autoHideMenuBar: true, autoHideMenuBar: true,
title: 'Krunker Civilian Client - Update', title: 'Krunker Civilian Client - Update',
webPreferences: { webPreferences: {
nodeIntegration: true, nodeIntegration: false,
contextIsolation: false, contextIsolation: true,
sandbox: false, sandbox: true,
}, },
}); });
win.removeMenu(); win.removeMenu();
@@ -88,7 +77,12 @@ export function showUpdateWindow(): { window: BrowserWindow; sendProgress: (mess
function sendProgress(message: string, percent?: number): void { function sendProgress(message: string, percent?: number): void {
if (!win.isDestroyed()) { if (!win.isDestroyed()) {
win.webContents.send('update-progress', message, percent); win.webContents.executeJavaScript(`(() => {
const s = document.getElementById('status');
const p = document.getElementById('progressBar');
if (s) s.textContent = ${JSON.stringify(message)};
if (p && typeof ${JSON.stringify(percent)} === 'number') p.style.width = ${JSON.stringify(percent)} + '%';
})()`).catch(() => {});
} }
} }