Code audit fixes: - CRITICAL: reorder Markdown pipeline (fixImages before sanitize) - CRITICAL: fix path prefix separator check - BLOCKING: remove duplicate useEffect in Editor - BLOCKING: skip onChange when content unchanged - BLOCKING: optimize Sidebar re-render with useMemo - HIGH: cleanup FileWatcher polling intervals - HIGH: improve validatePath segment check - HIGH: fix isExternalUpdate race with counter - HIGH: add will-navigate / setWindowOpenHandler - HIGH: explicit strip in sanitize schema - MEDIUM: random temp file suffix instead of Date.now() - MEDIUM/LOW: add IndexedDB error boundaries - LOW: support UTF-16 BOM detection
71 lines
1.7 KiB
TypeScript
71 lines
1.7 KiB
TypeScript
import { BrowserWindow, app } from 'electron'
|
|
import { join } from 'path'
|
|
import { existsSync, statSync } from 'fs'
|
|
|
|
export function createWindow(): BrowserWindow {
|
|
const mainWindow = new BrowserWindow({
|
|
width: 1200,
|
|
height: 800,
|
|
minWidth: 800,
|
|
minHeight: 600,
|
|
icon: join(__dirname, '../assets/icon.ico'),
|
|
webPreferences: {
|
|
preload: join(__dirname, '../preload/index.js'),
|
|
contextIsolation: true,
|
|
nodeIntegration: false,
|
|
sandbox: true
|
|
},
|
|
titleBarStyle: 'default',
|
|
show: false
|
|
})
|
|
|
|
mainWindow.setMenu(null)
|
|
|
|
// H-04: 阻止窗口导航和弹出窗口,防止渲染进程绕过 CSP
|
|
mainWindow.webContents.on('will-navigate', (event) => {
|
|
event.preventDefault()
|
|
})
|
|
mainWindow.webContents.setWindowOpenHandler(() => ({ action: 'deny' }))
|
|
|
|
mainWindow.once('ready-to-show', () => {
|
|
mainWindow.show()
|
|
})
|
|
|
|
return mainWindow
|
|
}
|
|
|
|
export function setupSingleInstanceLock(
|
|
onSecondInstance: (filePath: string | null) => void
|
|
): boolean {
|
|
const gotTheLock = app.requestSingleInstanceLock()
|
|
if (!gotTheLock) {
|
|
app.quit()
|
|
return false
|
|
}
|
|
|
|
app.on('second-instance', (_event, commandLine) => {
|
|
const filePath = getFilePathFromArgs(commandLine)
|
|
onSecondInstance(filePath)
|
|
})
|
|
|
|
return true
|
|
}
|
|
|
|
// L-08: 使用静态导入 + 验证是文件而非目录
|
|
export function getFilePathFromArgs(args: string[]): string | null {
|
|
for (let i = 1; i < args.length; i++) {
|
|
const arg = args[i]
|
|
if (!arg.startsWith('--') && !arg.startsWith('-')) {
|
|
try {
|
|
if (existsSync(arg)) {
|
|
const s = statSync(arg)
|
|
if (s.isFile()) return arg
|
|
}
|
|
} catch {
|
|
// ignore
|
|
}
|
|
}
|
|
}
|
|
return null
|
|
}
|