Electron desktop app for Avigilon Alta Video camera proxy management. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
4.3 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
Alta Video Camera Proxy — an Electron desktop app that authenticates with Avigilon Alta Video deployments, discovers cameras, and launches external proxy executables (aware-cam-proxy-win.exe, aware-cam-proxy.exe) to establish camera connections. Windows-only due to the proxy executables.
Commands
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
No test framework is configured. No linter is configured.
Architecture
This is a vanilla Electron app (no React/Vue/framework). Four files form the entire application:
main.js → Electron main process: IPC handlers, API calls (axios), profile CRUD,
camera proxy process spawning, password encryption (CryptoJS + machine-derived key)
preload.js → contextBridge exposing window.electronAPI with typed IPC invoke 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
IPC Communication Pattern
All cross-process communication follows one pattern:
main.jsregisters handler:ipcMain.handle('channel-name', async (event, params) => { ... })preload.jsexposes it:channelName: (params) => ipcRenderer.invoke('channel-name', params)renderer.jscalls it:const result = await window.electronAPI.channelName(params)
All handlers return { success: boolean, message?: string, ...data }.
IPC Channels
| Channel | Purpose |
|---|---|
api-login |
POST /api/v1/dologin, returns cookies |
api-get-devices |
GET /api/v1/devices with cookie auth |
api-get-auth-info |
GET /api/v1/auth to verify session |
profiles-load/save/get/delete/update |
CRUD for ~/.alta-api-profiles.json |
camera-proxy-launch |
Spawns aware-cam-proxy-win.exe (user/pass method) |
camera-proxy-cookie-launch |
Spawns aware-cam-proxy.exe (cookie method) |
camera-proxy-stop |
Kills all proxy processes via taskkill/powershell |
camera-proxy-check |
Checks if proxy executable exists |
camera-proxy-version |
Runs proxy with -v flag |
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 proxy processes are tracked in two Maps: activeProxyConnections and activeCookieProxyConnections, keyed by device GUID. Max 2 simultaneous connections (MAX_PROXY_CONNECTIONS).
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 - Encryption key derived from machine identifiers (hostname, homedir, username) via SHA-256
- Legacy profiles auto-migrate from old static key on first load
- Clipboard is cleared 30 seconds after password copy
- Passwords never written to DOM; kept only in JS variables (
selectedProfile)
Profile Storage
Profiles stored at ~/.alta-api-profiles.json. Passwords encrypted with CryptoJS AES using a machine-derived key. The profiles-load handler strips passwords before sending to renderer; profiles-get decrypts for a specific profile when needed.
Key Conventions
- No inline event handlers in HTML — all use
addEventListenerin 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 === falseonly) clearDeviceList()must NOT clear proxy connection Maps (proxies may still be running)
External Executables
aware-cam-proxy-win.exe— username/password auth proxy (required)aware-cam-proxy.exe— cookie-based auth proxy (optional)
These are not bundled via npm. They must be in the app root directory.