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>
This commit is contained in:
Zac
2026-02-09 20:58:54 -05:00
parent e813607f63
commit 67437a0c46
11 changed files with 470 additions and 9 deletions
+43 -5
View File
@@ -4,7 +4,13 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
## 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.
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
- **GitHub**: https://github.com/PageZ948/Alta-Proxy-Tool (private)
- **Branch**: master
- **Git identity**: Zac <zpage948@gmail.com> (repo-local config)
## Commands
@@ -19,26 +25,43 @@ 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:
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)
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
All cross-process communication follows one 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 |
@@ -52,6 +75,7 @@ All handlers return `{ success: boolean, message?: string, ...data }`.
| `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)
@@ -68,11 +92,25 @@ Active proxy processes are tracked in two Maps: `activeProxyConnections` and `ac
- 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.
### Chrome Extension Cookie Bridge
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
@@ -86,4 +124,4 @@ Profiles stored at `~/.alta-api-profiles.json`. Passwords encrypted with CryptoJ
- `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.
These are not bundled via npm. They must be in the app root directory. They are gitignored along with `*.pdf`, `node_modules/`, and `dist/`.