Loading...
Loading...
Compare original and translation side by side
// preload.ts - SECURE pattern
contextBridge.exposeInMainWorld('electronAPI', {
loadPreferences: () => ipcRenderer.invoke('load-prefs'),
saveFile: (content: string) => ipcRenderer.invoke('save-file', content),
onUpdateCounter: (callback: (value: number) => void) => {
const handler = (_event: IpcRendererEvent, value: number) => callback(value);
ipcRenderer.on('update-counter', handler);
return () => ipcRenderer.removeListener('update-counter', handler);
}
});'self'// preload.ts - 安全模式
contextBridge.exposeInMainWorld('electronAPI', {
loadPreferences: () => ipcRenderer.invoke('load-prefs'),
saveFile: (content: string) => ipcRenderer.invoke('save-file', content),
onUpdateCounter: (callback: (value: number) => void) => {
const handler = (_event: IpcRendererEvent, value: number) => callback(value);
ipcRenderer.on('update-counter', handler);
return () => ipcRenderer.removeListener('update-counter', handler);
}
});'self'type IpcChannelMap = {
'load-prefs': { args: []; return: UserPreferences };
'save-file': { args: [content: string]; return: { success: boolean } };
};export const appRouter = t.router({
greeting: t.procedure
.input(z.object({ name: z.string() }))
.query(({ input }) => `Hello, ${input.name}!`),
});message{ success, data, error }type IpcChannelMap = {
'load-prefs': { args: []; return: UserPreferences };
'save-file': { args: [content: string]; return: { success: boolean } };
};export const appRouter = t.router({
greeting: t.procedure
.input(z.object({ name: z.string() }))
.query(({ input }) => `Hello, ${input.name}!`),
});message{ success, data, error }src/
├── main/ # Main process (Node.js environment)
│ ├── index.ts
│ └── ipc/ # IPC handlers
├── preload/ # Secure bridge via contextBridge
│ ├── index.ts
│ └── index.d.ts # TypeScript declarations for exposed APIs
└── renderer/ # React application (pure web, no Node access)
├── src/
└── index.htmlsrc/
├── main/ # 主进程(Node.js环境)
│ ├── index.ts
│ └── ipc/ # IPC处理器
├── preload/ # 通过contextBridge实现安全桥接
│ ├── index.ts
│ └── index.d.ts # 暴露API的TypeScript声明
└── renderer/ # React应用(纯Web环境,无Node权限)
├── src/
└── index.htmluseEffect(() => {
const cleanup = window.electronAPI.onUpdateCounter((value) => {
setCount(value);
});
return cleanup;
}, []);useEffect(() => {
const cleanup = window.electronAPI.onUpdateCounter((value) => {
setCount(value);
});
return cleanup;
}, []);| Category | Prefer | Avoid |
|---|---|---|
| Security | | |
| IPC | | |
| Preload | Typed function wrappers | Exposing raw |
| Build tool | electron-vite | webpack-based toolchains |
| Packaging | Electron Forge | Manual packaging |
| State | Zustand + electron-store | Redux for simple apps |
| Testing | Playwright E2E | Spectron (deprecated) |
| Updates | electron-updater | Manual update checks |
| Signing | CI-integrated code signing | Unsigned releases |
| CSP | HTTP headers, | No CSP |
| Error handling | Result type | Raw Error across IPC |
| Multi-window | Main process as state hub | Direct window-to-window |
| 分类 | 推荐 | 避免 |
|---|---|---|
| 安全 | | |
| IPC | | 使用 |
| 预加载脚本 | 类型化函数包装器 | 暴露原始 |
| 构建工具 | electron-vite | 基于webpack的工具链 |
| 打包 | Electron Forge | 手动打包 |
| 状态管理 | Zustand + electron-store | 简单应用使用Redux |
| 测试 | Playwright端到端测试 | Spectron(已废弃) |
| 更新 | electron-updater | 手动检查更新 |
| 签名 | CI集成式代码签名 | 未签名的发布包 |
| CSP | HTTP头,仅允许 | 未设置CSP |
| 错误处理 | 结果类型 | 跨IPC边界传递原始Error |
| 多窗口 | 主进程作为状态中心 | 窗口之间直接通信 |
const win = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, '../preload/index.js'),
contextIsolation: true,
sandbox: true,
nodeIntegration: false,
},
});const win = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, '../preload/index.js'),
contextIsolation: true,
sandbox: true,
nodeIntegration: false,
},
});export function registerFileHandlers(): void {
ipcMain.handle('save-file', async (_event, content: string) => {
try {
await fs.writeFile(filePath, content);
return { success: true, data: filePath };
} catch (err) {
return { success: false, error: (err as Error).message };
}
});
}export function registerFileHandlers(): void {
ipcMain.handle('save-file', async (_event, content: string) => {
try {
await fs.writeFile(filePath, content);
return { success: true, data: filePath };
} catch (err) {
return { success: false, error: (err as Error).message };
}
});
}| Anti-Pattern | Problem | Solution |
|---|---|---|
| XSS escalates to full RCE | Keep disabled (default) |
Exposing | Full IPC access from renderer | Wrap in contextBridge functions |
Missing | Renderer accesses preload scope | Keep enabled (default since Electron 12) |
| No code signing | OS security warnings, Gatekeeper blocks | Sign and notarize for all platforms |
| Preload has full Node.js access | Enable sandbox (default since Electron 20) |
| Unvalidated IPC arguments | Injection attacks from renderer | Validate with Zod or manual checks |
| Network-exposed local server | Always bind to |
| Missing CSP headers | Script injection vectors | Set strict CSP via HTTP headers |
| No IPC error serialization | Lost error context across boundary | Use Result type pattern |
| Spectron for testing | Deprecated, Electron 13 max | Use Playwright |
references/security/security-checklist.md| 反模式 | 问题 | 解决方案 |
|---|---|---|
| XSS攻击可升级为完全远程代码执行 | 保持禁用(默认配置) |
直接暴露 | 渲染进程拥有完整IPC访问权限 | 使用contextBridge包装函数 |
未启用 | 渲染进程可访问预加载脚本作用域 | 保持启用(Electron 12起默认配置) |
| 未进行代码签名 | 操作系统安全警告,Gatekeeper拦截 | 为所有平台进行签名和公证 |
| 预加载脚本拥有完整Node.js权限 | 启用沙箱(Electron 20起默认配置) |
| IPC参数未验证 | 渲染进程注入攻击 | 使用Zod或手动检查进行验证 |
绑定到 | 本地服务器暴露到网络 | 始终绑定到 |
| 缺少CSP头 | 脚本注入风险 | 通过HTTP头设置严格的CSP |
| IPC错误未序列化 | 跨边界丢失错误上下文 | 使用结果类型模式 |
| 使用Spectron测试 | 已废弃,最高支持Electron 13 | 使用Playwright |
references/security/security-checklist.mddeno run --allow-read scripts/analyze-security.ts <path> [options]
Options:
--strict Enable all checks
--json Output JSON for CI
-h, --help Show help
Examples:
# Analyze a project
deno run --allow-read scripts/analyze-security.ts ./src
# Strict mode for CI pipeline
deno run --allow-read scripts/analyze-security.ts ./src --strict --jsondeno run --allow-read scripts/analyze-security.ts <path> [options]
选项:
--strict 启用所有检查
--json 输出JSON格式用于CI
-h, --help 显示帮助信息
示例:
# 分析项目
deno run --allow-read scripts/analyze-security.ts ./src
# CI流水线使用严格模式
deno run --allow-read scripts/analyze-security.ts ./src --strict --jsondeno run --allow-read --allow-write scripts/scaffold-electron-app.ts [options]
Options:
--name <name> App name (required)
--path <path> Target directory (default: ./)
--with-react Include React setup
--with-trpc Include electron-trpc
--with-tests Include Playwright tests
Examples:
# Basic app with React
deno run --allow-read --allow-write scripts/scaffold-electron-app.ts \
--name "my-app" --with-react
# Full setup with trpc and tests
deno run --allow-read --allow-write scripts/scaffold-electron-app.ts \
--name "my-app" --with-react --with-trpc --with-testsdeno run --allow-read --allow-write scripts/scaffold-electron-app.ts [options]
选项:
--name <name> 应用名称(必填)
--path <path> 目标目录(默认: ./)
--with-react 包含React搭建
--with-trpc 包含electron-trpc
--with-tests 包含Playwright测试
示例:
# 带React的基础应用
deno run --allow-read --allow-write scripts/scaffold-electron-app.ts \
--name "my-app" --with-react
# 包含trpc和测试的完整搭建
deno run --allow-read --allow-write scripts/scaffold-electron-app.ts \
--name "my-app" --with-react --with-trpc --with-testsdeno run --allow-read --allow-write scripts/generate-ipc-types.ts [options]
Options:
--handlers <path> Path to IPC handler files
--output <path> Output path for type definitions
--validate Validate existing types match handlers
Examples:
# Generate types from handlers
deno run --allow-read --allow-write scripts/generate-ipc-types.ts \
--handlers ./src/main/ipc --output ./src/preload/ipc-types.d.ts
# Validate types in CI
deno run --allow-read scripts/generate-ipc-types.ts \
--handlers ./src/main/ipc --validatedeno run --allow-read --allow-write scripts/generate-ipc-types.ts [options]
选项:
--handlers <path> IPC处理器文件路径
--output <path> 类型定义输出路径
--validate 验证现有类型是否匹配处理器
示例:
# 从处理器生成类型
deno run --allow-read --allow-write scripts/generate-ipc-types.ts \
--handlers ./src/main/ipc --output ./src/preload/ipc-types.d.ts
# CI中验证类型
deno run --allow-read scripts/generate-ipc-types.ts \
--handlers ./src/main/ipc --validatereferences/security/context-isolation.mdreferences/security/csp-and-permissions.mdreferences/security/security-checklist.mdreferences/security/context-isolation.mdreferences/security/csp-and-permissions.mdreferences/security/security-checklist.mdreferences/ipc/typed-ipc.mdreferences/ipc/electron-trpc.mdreferences/ipc/error-serialization.mdreferences/ipc/typed-ipc.mdreferences/ipc/electron-trpc.mdreferences/ipc/error-serialization.mdreferences/architecture/project-structure.mdreferences/architecture/process-separation.mdreferences/architecture/multi-window-state.mdreferences/architecture/project-structure.mdreferences/architecture/process-separation.mdreferences/architecture/multi-window-state.mdreferences/integration/react-patterns.mdreferences/integration/state-management.mdreferences/integration/react-patterns.mdreferences/integration/state-management.mdreferences/packaging/code-signing.mdreferences/packaging/auto-updates.mdreferences/packaging/bundle-optimization.mdreferences/packaging/ci-cd-patterns.mdreferences/packaging/code-signing.mdreferences/packaging/auto-updates.mdreferences/packaging/bundle-optimization.mdreferences/packaging/ci-cd-patterns.mdreferences/testing/playwright-e2e.mdreferences/testing/unit-testing.mdreferences/testing/test-structure.mdreferences/testing/playwright-e2e.mdreferences/testing/unit-testing.mdreferences/testing/test-structure.mdreferences/tooling/electron-vite.mdreferences/tooling/electron-forge.mdreferences/tooling/tauri-comparison.mdreferences/tooling/electron-vite.mdreferences/tooling/electron-forge.mdreferences/tooling/tauri-comparison.mdassets/templates/main-process.ts.mdassets/templates/preload-script.ts.mdassets/templates/ipc-handler.ts.mdassets/templates/react-root.tsx.mdassets/templates/main-process.ts.mdassets/templates/preload-script.ts.mdassets/templates/ipc-handler.ts.mdassets/templates/react-root.tsx.mdassets/configs/electron-vite.config.ts.mdassets/configs/forge.config.js.mdassets/configs/tsconfig.json.mdassets/configs/playwright.config.ts.mdassets/configs/electron-vite.config.ts.mdassets/configs/forge.config.js.mdassets/configs/tsconfig.json.mdassets/configs/playwright.config.ts.mdassets/examples/typed-ipc-example.mdassets/examples/multi-window-example.mdassets/examples/typed-ipc-example.mdassets/examples/multi-window-example.md