docs: Enhance documentation across multiple modules for clarity and structure
- Updated CONFIGURATION.md to improve navigation and added mermaid diagrams for better visualization of processes. - Revised IPC_ARCHITECTURE.md to clarify the security model and added diagrams to illustrate the architecture. - Improved README.md files in core-api, core-events, core-i18n, and core-storage for consistency and clarity, including better descriptions and structural enhancements.
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
[← Back to Root](../../../README.md)
|
||||
|
||||
# IPC Architecture & Security Model
|
||||
|
||||
The Secure Communication Blueprint.
|
||||
@@ -23,44 +25,56 @@ The desktop wrapper enforces a **strict privilege separation** between three exe
|
||||
|
||||
### Trust Level Matrix
|
||||
|
||||
| Context | Trust Level | Privilege Scope | Security Guarantee |
|
||||
|---|---|---|---|
|
||||
| **Main Process** | Fully Trusted | Unrestricted Node.js access: filesystem, network, printers, OS APIs, child processes | Only code authored by the engineering team executes here |
|
||||
| **Preload Script** | Controlled | Restricted to `ipcRenderer.invoke()` and `ipcRenderer.send()` — no direct Node.js access | Executes in a **Hermetically Sealed Context** — isolated from both the Main Process globals and the Renderer's DOM |
|
||||
| **Renderer** | Untrusted | Standard browser sandbox — zero Node.js API surface | Designated as a **Zero-Trust Environment** — may execute third-party code, npm packages, or XSS payloads |
|
||||
| Context | Trust Level | Privilege Scope | Security Guarantee |
|
||||
| ------------------ | ------------- | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
||||
| **Main Process** | Fully Trusted | Unrestricted Node.js access: filesystem, network, printers, OS APIs, child processes | Only code authored by the engineering team executes here |
|
||||
| **Preload Script** | Controlled | Restricted to `ipcRenderer.invoke()` and `ipcRenderer.send()` — no direct Node.js access | Executes in a **Hermetically Sealed Context** — isolated from both the Main Process globals and the Renderer's DOM |
|
||||
| **Renderer** | Untrusted | Standard browser sandbox — zero Node.js API surface | Designated as a **Zero-Trust Environment** — may execute third-party code, npm packages, or XSS payloads |
|
||||
|
||||
### Process Topology
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ MAIN PROCESS [Fully Trusted] │
|
||||
│ │
|
||||
│ UNRESTRICTED PRIVILEGES │
|
||||
│ Filesystem · Network · Printers · Native APIs · Child Processes │
|
||||
│ Auto-Updater · OS Integration · System Notifications │
|
||||
│ │
|
||||
│ ipcMain.handle('channel', handler) ← Command handlers │
|
||||
│ ipcMain.on('channel', handler) ← Event listeners │
|
||||
│ webContents.send('channel', data) ← Downstream push │
|
||||
├───────────── Non-Bypassable Isolation Boundary ─────────────────┤
|
||||
│ PRELOAD SCRIPT [Secure Gateway] │
|
||||
│ │
|
||||
│ HERMETICALLY SEALED CONTEXT │
|
||||
│ Performs Interface Narrowing: transforms broad IPC capabilities │
|
||||
│ into a minimal, auditable API surface. Acts as the sole │
|
||||
│ authorized mediator between trusted and untrusted contexts. │
|
||||
│ │
|
||||
│ contextBridge.exposeInMainWorld('electronAPI', { ... }) │
|
||||
├───────────── Non-Bypassable Isolation Boundary ─────────────────┤
|
||||
│ RENDERER [Zero-Trust Environment] │
|
||||
│ │
|
||||
│ UNTRUSTED WEB CONTENT │
|
||||
│ Standard browser sandbox. Zero access to: require, __dirname, │
|
||||
│ process, fs, child_process, net, os, ipcRenderer. │
|
||||
│ │
|
||||
│ ONLY authorized interaction vector: │
|
||||
│ window.electronAPI.methodName(args) │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
```mermaid
|
||||
graph TD
|
||||
%% ─── Styling Definitions (Dark-Mode Friendly Enterprise Palette) ───
|
||||
classDef trustedLayer fill:#f8fafc,stroke:#3b82f6,stroke-width:2px,color:#0f172a
|
||||
classDef gatewayLayer fill:#f0fdf4,stroke:#10b981,stroke-width:2px,color:#064e3b
|
||||
classDef untrustedLayer fill:#fef2f2,stroke:#ef4444,stroke-width:2px,color:#7f1d1d
|
||||
classDef functionNode fill:#e2e8f0,stroke:#64748b,stroke-width:2px,color:#0f172a
|
||||
|
||||
%% ─── Subgraphs ───
|
||||
subgraph Main ["MAIN PROCESS [Fully Trusted]"]
|
||||
M_DESC["Unrestricted Node.js Privileges"]
|
||||
IPC_MAIN_H[ipcMain.handle]
|
||||
IPC_MAIN_O[ipcMain.on]
|
||||
end
|
||||
|
||||
subgraph Preload ["PRELOAD SCRIPT [Secure Gateway]"]
|
||||
P_DESC["Hermetically Sealed Context (Interface Narrowing)"]
|
||||
CTX_BRIDGE{contextBridge.exposeInMainWorld}
|
||||
end
|
||||
|
||||
subgraph Renderer ["RENDERER [Zero-Trust Environment]"]
|
||||
R_DESC["Standard Browser Sandbox (No Node.js APIs)"]
|
||||
E_API([window.electronAPI])
|
||||
end
|
||||
|
||||
%% ─── Flow & Relationships ───
|
||||
E_API ===>|Only Authorized Vector| CTX_BRIDGE
|
||||
CTX_BRIDGE --->|Transforms to narrow IPC calls| IPC_MAIN_H
|
||||
CTX_BRIDGE --->|Transforms to narrow IPC calls| IPC_MAIN_O
|
||||
|
||||
%% ─── Apply Styles ───
|
||||
class Main trustedLayer;
|
||||
class Preload gatewayLayer;
|
||||
class Renderer untrustedLayer;
|
||||
class M_DESC,P_DESC,R_DESC,IPC_MAIN_H,IPC_MAIN_O functionNode;
|
||||
class CTX_BRIDGE gatewayLayer;
|
||||
class E_API untrustedLayer;
|
||||
|
||||
%% ─── Subgraph Backgrounds (Transparent for Native GitHub Support) ───
|
||||
style Main fill:transparent,stroke:#3b82f6,stroke-width:2px,stroke-dasharray: 5 5
|
||||
style Preload fill:transparent,stroke:#10b981,stroke-width:2px,stroke-dasharray: 5 5
|
||||
style Renderer fill:transparent,stroke:#ef4444,stroke-width:2px,stroke-dasharray: 5 5
|
||||
```
|
||||
|
||||
The Preload Script functions as a **Secure Gateway** that performs **Interface Narrowing** — it transforms the broad, unrestricted IPC capabilities of the Main Process into a deliberately narrow, type-safe API surface. The renderer communicates with native functionality **exclusively** through this gateway. There are no alternative paths, no escape hatches, and no backdoors.
|
||||
@@ -69,12 +83,12 @@ The Preload Script functions as a **Secure Gateway** that performs **Interface N
|
||||
|
||||
These settings are declared in `BrowserWindow.webPreferences` and are **non-negotiable**:
|
||||
|
||||
| Setting | Value | Enforcement |
|
||||
|---|---|---|
|
||||
| `contextIsolation` | `true` | The Preload executes in a hermetically sealed V8 context. The renderer **cannot** access `require()`, Node.js globals, or any variable from the preload's scope. |
|
||||
| `nodeIntegration` | `false` | **Zero** Node.js API surface in the renderer. `fs`, `child_process`, `os`, `net`, and all built-in modules are completely unavailable. |
|
||||
| `sandbox` | `true` | The renderer process runs inside a **Chromium OS-level sandbox**, restricting system calls and file access at the kernel level. |
|
||||
| `webSecurity` | `true` | The same-origin policy is **strictly enforced**, preventing cross-origin data exfiltration from the renderer. |
|
||||
| Setting | Value | Enforcement |
|
||||
| ------------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `contextIsolation` | `true` | The Preload executes in a hermetically sealed V8 context. The renderer **cannot** access `require()`, Node.js globals, or any variable from the preload's scope. |
|
||||
| `nodeIntegration` | `false` | **Zero** Node.js API surface in the renderer. `fs`, `child_process`, `os`, `net`, and all built-in modules are completely unavailable. |
|
||||
| `sandbox` | `true` | The renderer process runs inside a **Chromium OS-level sandbox**, restricting system calls and file access at the kernel level. |
|
||||
| `webSecurity` | `true` | The same-origin policy is **strictly enforced**, preventing cross-origin data exfiltration from the renderer. |
|
||||
|
||||
---
|
||||
|
||||
@@ -82,8 +96,7 @@ These settings are declared in `BrowserWindow.webPreferences` and are **non-nego
|
||||
|
||||
Every native feature in this architecture **must** follow the Three-Step Bridge — a Standard Operating Procedure (SOP) that ensures traceability, type-safety, and auditability across the entire IPC surface.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **Deterministic Synchronization**: Maintaining parity between the Main Process handler, the Preload Gateway exposure, and the TypeScript interface declaration is **mandatory**. A mismatch between any two of the three layers will result in either a **Type-Safety Gap** (silent failures in development) or a **Runtime Regression** (crashes in production).
|
||||
> [!IMPORTANT] > **Deterministic Synchronization**: Maintaining parity between the Main Process handler, the Preload Gateway exposure, and the TypeScript interface declaration is **mandatory**. A mismatch between any two of the three layers will result in either a **Type-Safety Gap** (silent failures in development) or a **Runtime Regression** (crashes in production).
|
||||
|
||||
### Step 1: Register the Handler — Main Process
|
||||
|
||||
@@ -134,6 +147,7 @@ contextBridge.exposeInMainWorld('electronAPI', electronAPI);
|
||||
```
|
||||
|
||||
**Non-negotiable rules:**
|
||||
|
||||
- **Never** expose `ipcRenderer` directly — this is a **Catastrophic Failure** pattern.
|
||||
- **Never** expose `ipcRenderer.on` without cleanup — use `createEventSubscription()`, which returns an unsubscribe function for React `useEffect` lifecycle management.
|
||||
- **Always** declare explicit TypeScript types for all function signatures.
|
||||
@@ -160,17 +174,18 @@ The following is the **complete, authoritative registry** of all authorized IPC
|
||||
|
||||
### Printer Subsystem
|
||||
|
||||
| Channel | Direction | Pattern | Payload | Access Control |
|
||||
|---|---|---|---|---|
|
||||
| `printer:get-list` | Renderer → Main → Renderer | `invoke` / `handle` | Returns `ElectronPrinterInfo[]` | Read-only hardware enumeration |
|
||||
| `printer:print` | Renderer → Main → Renderer | `invoke` / `handle` | Accepts `ElectronPrintOptions`, returns `{ success, failureReason? }` | Controlled hardware invocation |
|
||||
| Channel | Direction | Pattern | Payload | Access Control |
|
||||
| ------------------ | -------------------------- | ------------------- | --------------------------------------------------------------------- | ------------------------------ |
|
||||
| `printer:get-list` | Renderer → Main → Renderer | `invoke` / `handle` | Returns `ElectronPrinterInfo[]` | Read-only hardware enumeration |
|
||||
| `printer:print` | Renderer → Main → Renderer | `invoke` / `handle` | Accepts `ElectronPrintOptions`, returns `{ success, failureReason? }` | Controlled hardware invocation |
|
||||
|
||||
**Main process handler:** `setupPrinterIPC()` in `src/main/index.ts`
|
||||
|
||||
**Preload Gateway surface:**
|
||||
|
||||
```typescript
|
||||
getPrinters: () => ipcRenderer.invoke('printer:get-list')
|
||||
print: (options?) => ipcRenderer.invoke('printer:print', options)
|
||||
getPrinters: () => ipcRenderer.invoke('printer:get-list');
|
||||
print: (options?) => ipcRenderer.invoke('printer:print', options);
|
||||
```
|
||||
|
||||
**React consumption hook:** `useElectronPrinter()` in `apps/web/src/hooks/use-electron-printer.ts`
|
||||
@@ -179,16 +194,16 @@ print: (options?) => ipcRenderer.invoke('printer:print', options)
|
||||
|
||||
### Auto-Updater Subsystem
|
||||
|
||||
| Channel | Direction | Pattern | Payload | Access Control |
|
||||
|---|---|---|---|---|
|
||||
| `updater:check` | Renderer → Main | `invoke` / `handle` | Returns update check result | Read-only version query |
|
||||
| `updater:install` | Renderer → Main | `send` / `on` | No payload | Privileged: quits app and installs |
|
||||
| `updater:checking` | Main → Renderer | `send` | No payload | Status notification |
|
||||
| `updater:available` | Main → Renderer | `send` | `UpdateInfo { version, releaseDate, releaseNotes }` | Status notification |
|
||||
| `updater:not-available` | Main → Renderer | `send` | `UpdateInfo` | Status notification |
|
||||
| `updater:progress` | Main → Renderer | `send` | `ProgressInfo { percent, bytesPerSecond, transferred, total }` | Progress telemetry |
|
||||
| `updater:downloaded` | Main → Renderer | `send` | `UpdateInfo` | Status notification |
|
||||
| `updater:error` | Main → Renderer | `send` | Error message string | Error telemetry |
|
||||
| Channel | Direction | Pattern | Payload | Access Control |
|
||||
| ----------------------- | --------------- | ------------------- | -------------------------------------------------------------- | ---------------------------------- |
|
||||
| `updater:check` | Renderer → Main | `invoke` / `handle` | Returns update check result | Read-only version query |
|
||||
| `updater:install` | Renderer → Main | `send` / `on` | No payload | Privileged: quits app and installs |
|
||||
| `updater:checking` | Main → Renderer | `send` | No payload | Status notification |
|
||||
| `updater:available` | Main → Renderer | `send` | `UpdateInfo { version, releaseDate, releaseNotes }` | Status notification |
|
||||
| `updater:not-available` | Main → Renderer | `send` | `UpdateInfo` | Status notification |
|
||||
| `updater:progress` | Main → Renderer | `send` | `ProgressInfo { percent, bytesPerSecond, transferred, total }` | Progress telemetry |
|
||||
| `updater:downloaded` | Main → Renderer | `send` | `UpdateInfo` | Status notification |
|
||||
| `updater:error` | Main → Renderer | `send` | Error message string | Error telemetry |
|
||||
|
||||
**Main process handlers:** `setupAutoUpdaterIPC()` + `setupAutoUpdaterEvents()` in `src/main/index.ts`
|
||||
|
||||
@@ -283,7 +298,7 @@ contextBridge.exposeInMainWorld('ipc', ipcRenderer);
|
||||
contextBridge.exposeInMainWorld('require', require);
|
||||
```
|
||||
|
||||
**Threat:** The renderer can `require('child_process').exec('rm -rf /')`. A single XSS vulnerability in *any* dependency — including transitive ones — escalates to **full filesystem access, credential theft, reverse shells, and data exfiltration**.
|
||||
**Threat:** The renderer can `require('child_process').exec('rm -rf /')`. A single XSS vulnerability in _any_ dependency — including transitive ones — escalates to **full filesystem access, credential theft, reverse shells, and data exfiltration**.
|
||||
|
||||
**Classification:** **Total System Compromise**
|
||||
|
||||
@@ -294,7 +309,7 @@ contextBridge.exposeInMainWorld('require', require);
|
||||
```typescript
|
||||
// VIOLATION: Catastrophic Failure — Complete Boundary Collapse
|
||||
new BrowserWindow({
|
||||
webPreferences: { nodeIntegration: true, contextIsolation: false }
|
||||
webPreferences: { nodeIntegration: true, contextIsolation: false },
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user