fix: harden production electron app behavior
- No developer tools or zoom - No refresh window - Open links externally
This commit is contained in:
+67
-6
@@ -5,12 +5,14 @@ import { updateElectronApp, UpdateSourceType } from 'update-electron-app';
|
|||||||
|
|
||||||
import type { LinkMetadata } from './lib/link-metadata';
|
import type { LinkMetadata } from './lib/link-metadata';
|
||||||
|
|
||||||
updateElectronApp({
|
if (app.isPackaged) {
|
||||||
updateSource: {
|
updateElectronApp({
|
||||||
type: UpdateSourceType.StaticStorage,
|
updateSource: {
|
||||||
baseUrl: `https://storage.googleapis.com/flowy-releases/llink/${process.platform}/${process.arch}`
|
type: UpdateSourceType.StaticStorage,
|
||||||
}
|
baseUrl: `https://storage.googleapis.com/flowy-releases/llink/${process.platform}/${process.arch}`
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
|
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
|
||||||
if (started) {
|
if (started) {
|
||||||
@@ -27,6 +29,61 @@ let autoplayWindow: BrowserWindow | null = null;
|
|||||||
let huddleWindow: BrowserWindow | null = null;
|
let huddleWindow: BrowserWindow | null = null;
|
||||||
let screenRecordWindow: BrowserWindow | null = null;
|
let screenRecordWindow: BrowserWindow | null = null;
|
||||||
|
|
||||||
|
function hardenWindow(win: BrowserWindow) {
|
||||||
|
const wc = win.webContents;
|
||||||
|
|
||||||
|
// Disable pinch / Cmd+scroll zoom; our layouts assume DPR=1.
|
||||||
|
wc.setVisualZoomLevelLimits(1, 1);
|
||||||
|
|
||||||
|
// Block devtools, reload, and zoom keyboard shortcuts in packaged builds.
|
||||||
|
wc.on('before-input-event', (event, input) => {
|
||||||
|
if (input.type !== 'keyDown') return;
|
||||||
|
const key = input.key.toLowerCase();
|
||||||
|
const cmdOrCtrl = input.meta || input.control;
|
||||||
|
|
||||||
|
const isDevtools =
|
||||||
|
key === 'f12' ||
|
||||||
|
(cmdOrCtrl && input.alt && key === 'i') ||
|
||||||
|
(cmdOrCtrl && input.shift && key === 'i') ||
|
||||||
|
(cmdOrCtrl && input.shift && key === 'c') ||
|
||||||
|
(cmdOrCtrl && input.shift && key === 'j');
|
||||||
|
const isReload = cmdOrCtrl && (key === 'r' || key === 'f5');
|
||||||
|
const isZoom = cmdOrCtrl && (key === '=' || key === '+' || key === '-' || key === '0');
|
||||||
|
|
||||||
|
if (app.isPackaged && (isDevtools || isReload)) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
if (isZoom) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Route window.open / target=_blank through the OS browser instead of a new BrowserWindow.
|
||||||
|
wc.setWindowOpenHandler(({ url }) => {
|
||||||
|
if (url.startsWith('http://') || url.startsWith('https://')) {
|
||||||
|
shell.openExternal(url);
|
||||||
|
}
|
||||||
|
return { action: 'deny' };
|
||||||
|
});
|
||||||
|
|
||||||
|
// Freeze the window to its initial origin — block any full-page navigation.
|
||||||
|
// In-app routing uses pushState / hash which don't trigger will-navigate.
|
||||||
|
wc.on('will-navigate', (event, url) => {
|
||||||
|
const currentUrl = wc.getURL();
|
||||||
|
if (!currentUrl) return;
|
||||||
|
try {
|
||||||
|
if (new URL(url).origin !== new URL(currentUrl).origin) {
|
||||||
|
event.preventDefault();
|
||||||
|
if (url.startsWith('http://') || url.startsWith('https://')) {
|
||||||
|
shell.openExternal(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const createWindow = () => {
|
const createWindow = () => {
|
||||||
mainWindow = new BrowserWindow({
|
mainWindow = new BrowserWindow({
|
||||||
width: 800,
|
width: 800,
|
||||||
@@ -39,6 +96,7 @@ const createWindow = () => {
|
|||||||
backgroundThrottling: false,
|
backgroundThrottling: false,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
hardenWindow(mainWindow);
|
||||||
|
|
||||||
if (MAIN_WINDOW_VITE_DEV_SERVER_URL) {
|
if (MAIN_WINDOW_VITE_DEV_SERVER_URL) {
|
||||||
mainWindow.loadURL(MAIN_WINDOW_VITE_DEV_SERVER_URL);
|
mainWindow.loadURL(MAIN_WINDOW_VITE_DEV_SERVER_URL);
|
||||||
@@ -72,6 +130,7 @@ const createAutoplayWindow = () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
autoplayWindow.setVisibleOnAllWorkspaces(true);
|
autoplayWindow.setVisibleOnAllWorkspaces(true);
|
||||||
|
hardenWindow(autoplayWindow);
|
||||||
|
|
||||||
if (AUTOPLAY_WINDOW_VITE_DEV_SERVER_URL) {
|
if (AUTOPLAY_WINDOW_VITE_DEV_SERVER_URL) {
|
||||||
autoplayWindow.loadURL(AUTOPLAY_WINDOW_VITE_DEV_SERVER_URL);
|
autoplayWindow.loadURL(AUTOPLAY_WINDOW_VITE_DEV_SERVER_URL);
|
||||||
@@ -103,6 +162,7 @@ const createHuddleWindow = () => {
|
|||||||
preload: path.join(__dirname, 'preload.js'),
|
preload: path.join(__dirname, 'preload.js'),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
hardenWindow(huddleWindow);
|
||||||
|
|
||||||
if (HUDDLE_WINDOW_VITE_DEV_SERVER_URL) {
|
if (HUDDLE_WINDOW_VITE_DEV_SERVER_URL) {
|
||||||
huddleWindow.loadURL(HUDDLE_WINDOW_VITE_DEV_SERVER_URL);
|
huddleWindow.loadURL(HUDDLE_WINDOW_VITE_DEV_SERVER_URL);
|
||||||
@@ -147,6 +207,7 @@ const createScreenRecordWindow = () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
screenRecordWindow.setVisibleOnAllWorkspaces(true);
|
screenRecordWindow.setVisibleOnAllWorkspaces(true);
|
||||||
|
hardenWindow(screenRecordWindow);
|
||||||
|
|
||||||
if (SCREEN_RECORD_WINDOW_VITE_DEV_SERVER_URL) {
|
if (SCREEN_RECORD_WINDOW_VITE_DEV_SERVER_URL) {
|
||||||
screenRecordWindow.loadURL(SCREEN_RECORD_WINDOW_VITE_DEV_SERVER_URL);
|
screenRecordWindow.loadURL(SCREEN_RECORD_WINDOW_VITE_DEV_SERVER_URL);
|
||||||
|
|||||||
Reference in New Issue
Block a user