Files
Alta-Proxy-Tool/CLAUDE.md
T
peji 67437a0c46 Add Chrome extension cookie bridge for session import
Users logged into Alta in Chrome can now send their session cookie
to the running Electron app via a local HTTP server on port 18247,
eliminating the need for re-authentication.

- main.js: HTTP cookie server with CORS, token, domain validation
- preload.js: onExtensionCookie push-pattern IPC bridge
- renderer.js: handleExtensionCookie sets session, fetches devices
- chrome-extension/: Manifest V3 extension with popup UI
- CLAUDE.md: updated architecture docs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 20:58:54 -05:00

6.3 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

Alta Proxy Tool (APT) — 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.

Repository

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). Core files:

main.js      → Electron main process: IPC handlers, API calls (axios), profile CRUD,
                camera proxy process spawning, password encryption (CryptoJS + machine-derived key),
                local HTTP cookie server for Chrome extension bridge
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

A companion Chrome extension lives in chrome-extension/:

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

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-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
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 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)
  • 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

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.

Users already logged into Alta in Chrome can send their va session cookie to the running Electron app. The flow:

  1. Chrome extension popup detects Alta tab (*.avasecurity.com / *.avigilon.com)
  2. User clicks "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, populates cookie key, expands cookie proxy section, fetches devices

The extension is loaded unpacked via chrome://extensions/ → Developer mode → Load unpacked → select chrome-extension/.

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 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. They are gitignored along with *.pdf, node_modules/, and dist/.