diff --git a/backend/src/main/resources/content/technical/browser/gotchas.md b/backend/src/main/resources/content/technical/browser/gotchas.md new file mode 100644 index 0000000..28c4eec --- /dev/null +++ b/backend/src/main/resources/content/technical/browser/gotchas.md @@ -0,0 +1,50 @@ +--- +module: technical.browser +title: HiveIQ Browser — Electron desktop client +tab: Gotchas +order: 40 +audience: dev +--- + +# Browser gotchas & diagnostics + +## The update check runs at startup only + +`checkForBrowserUpdate()` fires once at launch. If a user reports "no update prompt," first confirm +they **restarted** after the new version was published. The result is logged as +`Browser update check result { updateAvailable, latestVersion, currentVersion }` — read that line to +see exactly what their build resolved. + +## 2.4.7 / 2.4.8 have a permanently-broken updater + +Builds **2.4.7 and 2.4.8** (prod and dev) shipped a broken update checker: `_resolveUpdateChannel` +referenced `authManager` (for the old beta-channel role check), but `authManager` was only +`require`d locally inside `downloadAgent` — so the check threw **`ReferenceError: authManager is not +defined`**, which was swallowed and reported as `updateAvailable: false`. **These builds can never +self-prompt**, for any user/role — the fix (remove the beta channel, remove the dead +`_passesInstitutionGate`) shipped in **2.4.9**. Getting a 2.4.7/2.4.8 user current requires a +**manual reinstall** of 2.4.9 once; auto-update works from there. + +Bug introduced in `bca8f60` (2026-06-30, ~10 min before the 2.4.7 build); fixed in `8a5cd3a` + `cfbae6a`. + +## "Self signed certificate" on login = DNS, not code + +If the browser errors with a self-signed-certificate message, it's almost always a **DNS / `/etc/hosts` +pin** sending it to an internal (self-signed) endpoint instead of the public one — not a code bug. +Check the machine's hosts file / resolver before touching the app. + +## Stale refresh token → whitelabel screen on login + +An expired/stale refresh token can leave the user on a blank/whitelabel screen at login. Clearing the +stored auth (`clear-auth.sh` locally, or the app's stored tokens) recovers it. + +## Same-version re-release doesn't prompt + +Re-running the release for an unchanged version number overwrites the installer files but leaves +`latest.json` at the same version — so no client sees an update. Bump the version to trigger auto-update. + +## Diagnostics + +- Logs: `~/.config/hiveops-browser/logs/` (Linux) / `%APPDATA%/hiveops-browser/logs/` (Windows); + the **dev** build uses `hiveops-browser-dev`. +- `check-license-status.sh`, `clear-auth.sh`, `debug-launch.sh` are handy local helpers in the repo. diff --git a/backend/src/main/resources/content/technical/browser/overview.md b/backend/src/main/resources/content/technical/browser/overview.md new file mode 100644 index 0000000..b938936 --- /dev/null +++ b/backend/src/main/resources/content/technical/browser/overview.md @@ -0,0 +1,87 @@ +--- +module: technical.browser +title: HiveIQ Browser — Electron desktop client +tab: Overview +order: 10 +audience: dev +--- + +# HiveIQ Browser (`hiveops-browser`) + +An **Electron** desktop client — a restricted browser that only navigates authorized HiveIQ URLs, +with native license display, agent/software downloads, an in-app feedback form, and self-update. +Distributed as installers from the CDN (**not** a Docker image). Current line: `2.x` (2.4.9). + +## Build variants — prod vs dev + +The same codebase produces two isolated builds, selected by `BUILD_VARIANT` (`src/main/config.js`): + +- Resolved from `HIVEOPS_BUILD_VARIANT` env (local `npm start` override) → else + `package.json.buildVariant` (injected at package time via electron-builder `extraMetadata`) → else **`prod`**. +- **prod** (`electron-builder.yml`, `npm run build`) → points at `*.bcos.cloud`, config `config/prod.config.json`. +- **dev** (`build-dev.sh` + `electron-builder.dev.yml`, `extraMetadata.buildVariant=dev`) → points at + `*.bcos.dev`, config `config/dev.config.json`, output `dist-dev/`. +- The dev build gets a **separate OS identity** (`app.setName('hiveops-browser-dev')` → its own + `userData`, single-instance lock, protocol registration) so dev and prod can run side by side. +- **Safety:** in the dev build, `assertNoProdUrls()` refuses to start if any resolved config value + contains `bcos.cloud` (sets `global.DEV_CONFIG_ERROR`). + +## Config resolution (`src/main/config.js`) + +`loadProfileConfig()` reads the active profile JSON (`prod.config.json` / `dev.config.json`); the dev +build merges over a `devSafeBase` (no prod URLs), the prod build over `defaultConfig`. `config.get(key)` +re-reads the profile file for URL keys (`apiBaseUrl`, `authServerUrl`, `allowedUrl`, `browserUpdatePath`, +the per-app base URLs) so switching profiles takes effect without code changes. `releaseServerUrl` also +honors a user override stored in `electron-store`. + +Two client-shipped tokens live in config.js (not repo/Gitea creds): `FEEDBACK_SUBMIT_KEY` (write-only +feedback submit) and `CDN_TOKEN` (gated `/downloads/software/` + `/downloads/hotfix/`); both overridable +by env for rotation. + +## Auth — two clients, MFA lives in `hiveops-auth` + +`src/main/api-client.js` builds **two** axios instances, and **every** request from both carries +`X-HiveIQ-Browser-Version: ` (plus `X-HiveIQ-Browser: true`): + +- `getClient()` → `apiBaseUrl` (mgmt, `/mgmt/api/v1`). Its `login()` posts to `/auth/login`. +- `getAuthClient()` → `authServerUrl` + `/api` (hiveops-auth). **This is the real customer/MSP login + path**: `authLogin()` → optional MFA (`authVerifyMfa`, `authVerifyBackupCode`) → tokens. TOTP/backup + MFA is enforced by `hiveops-auth`. + +Because the version header is on every login, the backend can capture it — see the browser-version +tracking on the mgmt portal (`technical.mgmt`) and MSP users list (`technical.auth` `/msp/users`). + +## Self-update + +`checkForBrowserUpdate()` runs **at startup** (not a background timer): + +1. `_resolveUpdateChannel()` fetches the **general channel** manifest — + `${releaseServerUrl}${browserUpdatePath}/latest.json` (prod `cdn.bcos.cloud/downloads/browser`, + dev `cdn.bcos.dev/browser-dev`). **Beta/pre-release channels were removed** (2.4.9) — every user + updates from the one general channel. +2. `_isNewer(latest, current)` (semver-ish) decides; if newer, prompt. +3. Download from `${releaseServerUrl}/downloads/`. + +Because the check is **startup-only**, a user must restart to pick up a new version. + +## Menus & windows (`src/main/main.js`) + +- **Software** menu (Download Agent / Upload Hotfix / Upload Software) is shown **only to MSP_ADMIN / + BCOS_ADMIN**. +- **Help → About** (Info / License / Usage / Disclaimers tabs; License shows Status/Tier/masked + Key/Expires/Days-Remaining via `getLicenseInfo()`) and **Feedback** open as **modal** windows. +- Feedback form (`src/renderer/feedback.html`) offers Bug / Enhancement / Documentation / Incident + types with per-type templates, and stamps `reporterUserId` from the JWT `sub`; submits to + `/feedback/api/submit` (see `technical.feedback`). "What's New" popup was removed. + +## Release (CI is broken — build locally) + +`release.yml` tag-trigger fails, so releases are cut **locally** with electron-builder: + +- **Prod:** `npm run build:win` / `build:linux` → scp installers to CDN VM `173.231.195.252` → + `release-browser.sh ` (writes `downloads/browser/latest.json`). +- **Dev:** `build-dev.sh` → scp to `173.231.195.251` under `downloads/downloads/` → + `release-browser-dev.sh`. +- Re-releasing the **same version** overwrites files but does not bump the manifest → no auto-update prompt. + +See **`technical.browser` Gotchas** for the update-channel failure modes and the self-signed-cert red herring.