fix: harden Electron security (theme injection, update window, navigation)
This commit is contained in:
+11
-5
@@ -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));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(() => {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user