eat: implement Holesail-Browser enhancement plan
CI / Build & Test (push) Successful in 3m19s

- Add unit tests (hostname-validator, TLDs, payload-schemas) and integration tests for message handler registry
- Refactor native host message router into handler registry (handlers/state, tunnels, ssh, rdp, backup, ca, connections)
- Add ESLint config and npm test + lint steps in CI
- Dashboard: visibility-based refresh pause, configurable refresh interval (2s/5s/10s/paused)
- Accessibility: ARIA on nav and modals, focus trap and restore, prefers-reduced-motion
- Empty states: primary action buttons for virtual hosts, servers, service tunnels
- Native host rate limiting for backup and CA operations; update SECURITY.md
- CONTRIBUTING: "Adding a new dashboard page", dev workflow; add npm run dev script
This commit is contained in:
Raven Scott
2026-03-15 00:24:31 -04:00
parent 8df1ef3ec6
commit 6fcd9fcf2b
38 changed files with 2028 additions and 279 deletions
+30 -1
View File
@@ -181,6 +181,25 @@ chrome.runtime.sendMessage({
Add an entry under the Commands section with the request payload shape, response shape, and any notes on optional fields.
## Adding a new dashboard page
To add a new page to the dashboard (e.g. a new section in the sidebar and a full-page view):
1. **Add the page HTML** in `extension/dashboard/dashboard.html`: a `<div class="page" id="page-<key>">` with your content, and a sidebar nav item `<div class="nav-item" data-page="<key">` with icon and label.
2. **Register the page** in `extension/dashboard/core/navigation.js`: add an entry to `PAGE_TITLES` (e.g. `myPage: 'My Page Title'`).
3. **Create the page module** `extension/dashboard/pages/<name>.js` that exports:
- `update<Name>(state)` — called on every refresh with the full state; use it to re-render your table or widgets.
- `setup<Name>Events()` — called once at init; attach click handlers, form submit, etc.
4. **Wire the page into the dashboard**:
- In `extension/dashboard/refresh.js`, inside the `refresh()` function, call your `update<Name>(state)` after the existing `update*` calls.
- In `extension/dashboard/events.js`, inside `setupEvents()`, call your `setup<Name>Events()`.
- In `extension/dashboard/dashboard.html`, add a `<script src="pages/<name>.js">` in the same order as the other page scripts (before `refresh.js` and `init.js`).
5. **Optional**: if your page needs to request data from the native host, use `sendToNative(type, payload)` from `core/messaging.js` and ensure the native host has a handler for that message type (see "Adding a new native host message type" above).
## Code style
- **No build step for the extension** — the dashboard JS files are loaded directly by the browser in dependency order (see the `<script>` tags at the bottom of `dashboard.html`). There is no bundler or transpiler for the extension.
@@ -189,9 +208,19 @@ Add an entry under the Commands section with the request payload shape, response
- **Error handling** — all async functions should catch errors and return `{ ok: false, error: e.message }` rather than throwing, so the extension always gets a structured response.
- **Timers and listeners** — always store timer IDs and remove event listeners in cleanup paths to avoid leaks (see `docs/ARCHITECTURE.md` for the resource management patterns used throughout).
## Dev workflow
For a quick local development loop:
1. Run `npm run dev` to build the native host launcher and run the installer (so the native messaging manifest points to your build). This prints the path to the extension directory.
2. Open Chrome → `chrome://extensions` → enable **Developer mode****Load unpacked** → select the `extension/` directory.
3. After code changes: reload the extension from `chrome://extensions`; for native host changes, run `npm run build:host` again and reload the extension so the host restarts.
To run only the host build without installing: `npm run build:host`. To run the full installer: `npm run setup`.
## Testing
There is currently no automated test suite. Manual testing workflow:
There is an automated test suite for hostname validation, TLD data, payload schemas, and the message handler registry. Run `npm test`. Manual testing workflow:
1. Make changes to the native host source
2. Run `npm run build:host` to regenerate the launcher
+3
View File
@@ -78,6 +78,8 @@ The native host runs as your user account (not root). It:
- Spawns child processes: `ssh` (for SSH sessions), `tar` (for backups), `security`/`certutil`/`pkexec` (for CA installation)
- Does not require elevated privileges for normal operation
The extension is trusted in the sense that it runs in the user's browser and can send any message to the native host. The native host **validates all incoming payloads** and applies **rate limits** to expensive or sensitive operations (backup create/restore/delete, CA install) to reduce the impact of a compromised extension (e.g. backup spam or CA install loops). See `native-host/host/rate-limit.js` for limits.
---
## Proxy security
@@ -126,6 +128,7 @@ This prevents accidentally routing real internet traffic through the local proxy
| Stale CA after reinstall causing cert errors | Fingerprint verification on every CA install check |
| Multiple native host instances with no tunnels | Process exits on EADDRINUSE; only one instance owns the ports |
| Custom TLD colliding with real internet domain | TLD blocklist validation in dashboard before saving |
| Compromised extension spamming backups or CA install | Rate limits (e.g. max 3 backup creates, 5 CA installs per minute) |
## Threats not mitigated