fix: integrate hardened APT security boundary
This commit is contained in:
@@ -1,112 +1,50 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
## Project
|
||||
|
||||
## Project Overview
|
||||
Alta Proxy Tool (APT) is a Windows-only Electron app. Its source of record and releases are on GitPeji:
|
||||
|
||||
Alta Proxy Tool (APT) — an Electron desktop app that authenticates with Avigilon Alta Video deployments via a companion Chrome extension, discovers cameras, and launches `aware-cam-proxy.exe` to establish camera connections. Authentication uses cookie import from Chrome — no username/password login flow. Windows-only due to the proxy executable.
|
||||
- Repository: `https://git.pejicorp.com/peji/Alta-Proxy-Tool`
|
||||
- Releases: `https://git.pejicorp.com/peji/Alta-Proxy-Tool/releases`
|
||||
|
||||
## Repository
|
||||
|
||||
- **GitHub**: https://github.com/PageZ948/Alta-Proxy-Tool (private)
|
||||
- **Branch**: master
|
||||
- **Git identity**: Zac <zpage948@gmail.com> (repo-local config)
|
||||
The app imports an Alta Video session through a stable-ID paired Chrome extension, discovers cameras, and directly launches the fixed `aware-cam-proxy.exe` helper.
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
npm start # Run the app
|
||||
npm run dev # Run with DevTools open (--dev flag)
|
||||
npm run build # Build portable Windows .exe (output: dist/)
|
||||
npm run build-test # Build to directory without packaging
|
||||
npm start
|
||||
npm run dev
|
||||
npm test
|
||||
npm run check
|
||||
npm run build-test
|
||||
npm run build
|
||||
```
|
||||
|
||||
No test framework is configured. No linter is configured.
|
||||
## Required security architecture
|
||||
|
||||
## Architecture
|
||||
- Main owns `SessionStore`, `AltaClient`, `ProxyProcessManager`, bridge authentication, and safe update checking.
|
||||
- Renderer/preload contracts must never carry the Alta deployment credential or cookie.
|
||||
- IPC methods are narrow and sender-validated against the main local file frame.
|
||||
- Bridge is exactly `127.0.0.1:18247`, exact committed extension origin, and `X-APT-Pairing` authenticated.
|
||||
- Persist only the pairing hash envelope under Electron `userData`; plaintext is shown once after first run/rotation.
|
||||
- Proxy helper launches directly with `shell: false`; stop only app-owned child processes.
|
||||
- Update behavior is check-only against the exact GitPeji API. The only follow-up action opens the fixed GitPeji releases page externally.
|
||||
- Never add download/install/replace logic, arbitrary URLs, redirect following, shell scripts, broad process killing, hardcoded bridge secrets, or credential-bearing renderer state.
|
||||
- Synthetic tests only: never use a real tenant or Alta session.
|
||||
|
||||
This is a vanilla Electron app (no React/Vue/framework). Core files:
|
||||
## File map
|
||||
|
||||
```
|
||||
main.js → Electron main process: IPC handlers, API calls (axios),
|
||||
cookie proxy process spawning, local HTTP cookie server
|
||||
preload.js → contextBridge exposing window.electronAPI with IPC wrappers
|
||||
renderer.js → All UI logic: DOM manipulation, state management, event handlers
|
||||
index.html → Static HTML shell, no inline scripts (CSP enforced)
|
||||
styles.css → Dark theme using CSS custom properties
|
||||
```
|
||||
- `main.js`: Electron adapter, lifecycle, trusted IPC registration, fixed bridge listener
|
||||
- `src/electron-runtime.js`: runtime orchestration, pairing persistence, bridge request contract
|
||||
- `src/session-store.js`: in-memory credential boundary
|
||||
- `src/alta-client.js`: bounded same-origin Alta API client
|
||||
- `src/proxy-launch.js`: Windows direct-spawn owned-child manager
|
||||
- `src/update-policy.js`: GitPeji check-only policy
|
||||
- `src/bridge-auth.js`: stable extension origin, scrypt pairing, limits/deadlines
|
||||
- `preload.js`: narrow methods and event payload stripping
|
||||
- `renderer.js`: non-secret connection/device/proxy/pairing/update UI
|
||||
- `test/runtime-contract.test.js`: integration and forbidden-source policy
|
||||
|
||||
A companion Chrome extension lives in `chrome-extension/`:
|
||||
## Scope
|
||||
|
||||
```
|
||||
chrome-extension/
|
||||
manifest.json → Manifest V3, cookies + activeTab permissions
|
||||
popup.html → Extension popup UI
|
||||
popup.css → Dark theme matching the Electron app
|
||||
popup.js → Tab detection, cookie retrieval, POST to localhost
|
||||
icon*.png → Placeholder icons
|
||||
```
|
||||
|
||||
### Authentication Flow
|
||||
|
||||
There is no login form or profile system. Authentication works exclusively through the Chrome extension cookie bridge:
|
||||
|
||||
1. User logs into Alta deployment in Chrome
|
||||
2. Clicks the Chrome extension popup → "Send Cookie to APT"
|
||||
3. Extension POSTs `{deploymentUrl, cookieValue}` to `http://127.0.0.1:18247/cookie` with `X-APT-Token` header
|
||||
4. `main.js` HTTP server validates and forwards via IPC push to renderer
|
||||
5. `renderer.js` `handleExtensionCookie()` sets session state, auto-populates cookie key, fetches devices
|
||||
|
||||
The extension is loaded unpacked via `chrome://extensions/` → Developer mode → Load unpacked → select `chrome-extension/`.
|
||||
|
||||
### IPC Communication Pattern
|
||||
|
||||
Most cross-process communication follows the request/response pattern:
|
||||
1. `main.js` registers handler: `ipcMain.handle('channel-name', async (event, params) => { ... })`
|
||||
2. `preload.js` exposes it: `channelName: (params) => ipcRenderer.invoke('channel-name', params)`
|
||||
3. `renderer.js` calls it: `const result = await window.electronAPI.channelName(params)`
|
||||
|
||||
All handlers return `{ success: boolean, message?: string, ...data }`.
|
||||
|
||||
There is one **push-pattern** channel for the Chrome extension cookie bridge:
|
||||
- `main.js` sends: `mainWindow.webContents.send('extension-cookie-received', data)`
|
||||
- `preload.js` bridges: `ipcRenderer.on('extension-cookie-received', callback)`
|
||||
- `renderer.js` listens via `window.electronAPI.onExtensionCookie(callback)`
|
||||
|
||||
### IPC Channels
|
||||
|
||||
| Channel | Purpose |
|
||||
|---------|---------|
|
||||
| `api-get-devices` | GET /api/v1/devices with cookie auth |
|
||||
| `api-get-auth-info` | GET /api/v1/auth to verify session |
|
||||
| `camera-proxy-cookie-launch` | Spawns aware-cam-proxy.exe (cookie method) |
|
||||
| `camera-proxy-stop` | Kills all proxy processes via taskkill/powershell |
|
||||
| `extension-cookie-received` | Push channel: cookie data from Chrome extension → renderer |
|
||||
|
||||
### State Management (renderer.js)
|
||||
|
||||
All connection state lives in the `sessionData` object (deploymentUrl, cookies, isConnected). There is no separate `isConnected` flag — always use `sessionData.isConnected`.
|
||||
|
||||
Active cookie proxy processes are tracked in `activeCookieProxyConnections` Map, keyed by device GUID.
|
||||
|
||||
### Security Model
|
||||
|
||||
- Context isolation enabled, nodeIntegration disabled
|
||||
- CSP meta tag: `script-src 'self'` — no inline scripts or onclick handlers allowed
|
||||
- Batch file inputs are sanitized via `sanitizeBatchInput()` to prevent command injection
|
||||
- Local HTTP cookie server (port 18247) bound to `127.0.0.1` only
|
||||
- Cookie server validates: shared token header, CORS restricted to `chrome-extension://` origins, deployment URL must be `*.avasecurity.com` or `*.avigilon.com` over HTTPS, type/length limits on all inputs, 64KB body size limit
|
||||
|
||||
## Key Conventions
|
||||
|
||||
- No inline event handlers in HTML — all use `addEventListener` in renderer.js
|
||||
- All user-provided content rendered to DOM must go through `escapeHtml()` (XSS prevention)
|
||||
- External processes spawned with `detached: true` + `unref()` so they survive if the app closes
|
||||
- Device list filters out cloud cameras (`capabilities.localStorage === false` only)
|
||||
- `clearDeviceList()` must NOT clear proxy connection Maps (proxies may still be running)
|
||||
|
||||
## External Executable
|
||||
|
||||
- `aware-cam-proxy.exe` — cookie-based auth proxy (required)
|
||||
|
||||
Not bundled via npm. Must be in the app root directory. Gitignored along with `*.pdf`, `node_modules/`, and `dist/`.
|
||||
Windows is the current supported runtime because `aware-cam-proxy.exe` is Windows-specific. Do not upgrade dependencies or change production/Tool Hub as part of runtime hardening unless explicitly requested.
|
||||
|
||||
Reference in New Issue
Block a user