Files
desktop/apps/hanzo-desktop/src-tauri/tauri.conf.json
zeekayandGitHub c1424c617d fix(security): resolve red-team findings (IAM token persistence, CSP, log path) (#23)
Confirmed red-team findings in apps/hanzo-desktop:

1. HIGH — IAM login tokens never persisted during registration. The
   useInitialRegistration onSuccess closure read tokens from useHanzoLogin(),
   but the hook (a) was destructured AFTER useInitialRegistration and (b) had
   regressed to a `{ login }`-only API that no longer exposed `tokens` (4 latent
   TS2339 errors in terms-conditions.tsx). Restore the stateful hook API
   (login/startLogin/tokens/tokensRef/isLoading/error/resetState) and call it
   BEFORE useInitialRegistration. onSuccess now reads `tokensRef.current` — a
   closure-safe mirror of the reactive tokens — so a token obtained mid-flow is
   actually written into setAuth. Removed the duplicate useHanzoLogin() call and
   a stale, conflicting "spawn node when tokens arrive" effect that would have
   wrongly spawned a local node in cloud mode (isCloudMode).

2. MED — resetState exported but unused. Wired error/resetState into the login
   UI: a failed IAM login now shows an inline error with a Retry control
   (resetState() + retry), instead of only console.error.

3. MED — CSP disabled (app.security.csp: null). Set a real CSP: strict
   script-src 'self' (+ 'wasm-unsafe-eval' and jsdelivr for pyodide/sql.js),
   object-src 'none', base-uri/form-action 'self'. connect-src allows the local
   node (http + ws on 127.0.0.1/localhost), Tauri IPC, and is conservatively
   widened to https:/wss: because model-provider and web3 RPC endpoints are
   user-configurable and unbounded. Verified Tauri parses the config (tauri
   info reports the CSP). Shared security block covers all windows; preserved by
   the brand-build deep-merge (no overlay sets app.security).

4. MED — download_logs wrote to an arbitrary save_path via fs::copy. Added
   validate_save_path: canonicalize the destination's parent (resolving
   ../symlinks) and reject anything outside the user's home dir, then copy to
   the validated path. Keeps the legit dialog-chosen path working.

Deferred (out of scope, noted in PR): WalletData plaintext zeroization — a
cross-cutting refactor of the node API contract.

Verified: tsc -b apps/hanzo-desktop/tsconfig.json --noEmit drops from 31 to 27
unique errors (the 4 terms-conditions.tsx errors resolved, 0 new); cargo check
on src-tauri finishes with 0 errors.
2026-06-25 15:21:53 -07:00

124 lines
3.7 KiB
JSON

{
"build": {
"beforeDevCommand": "npm run dev",
"beforeBuildCommand": "npm run build:ci",
"frontendDist": "../dist",
"devUrl": "http://localhost:1420"
},
"bundle": {
"active": true,
"targets": ["app", "appimage", "nsis", "dmg"],
"externalBin": [
"external-binaries/hanzo-node/hanzo-node",
"external-binaries/hanzo-node/hanzo-tools-runner-resources/deno",
"external-binaries/hanzo-node/hanzo-tools-runner-resources/uv"
],
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/[email protected]",
"icons/icon.icns",
"icons/icon.ico"
],
"resources": ["llm-models/"],
"macOS": {
"minimumSystemVersion": "12.0"
},
"createUpdaterArtifacts": "v1Compatible"
},
"productName": "Hanzo",
"version": "../../../package.json",
"identifier": "ai.hanzo.desktop",
"plugins": {
"updater": {
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDE4OURBNzhCM0Q2RTMwMzIKUldReU1HNDlpNmVkR01uQXpJaS9Dd2gvRlpsbDVYQmg0MlJSUnNib2tSOW5qRG5zSVdsMW0zZm8K",
"endpoints": [
"https://github.com/hanzoai/desktop/releases/latest/download/latest.json"
],
"windows": {
"installMode": "basicUi"
}
},
"deep-link": {
"desktop": {
"schemes": ["hanzo"]
}
}
},
"app": {
"withGlobalTauri": false,
"security": {
"csp": "default-src 'self'; script-src 'self' 'wasm-unsafe-eval' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; img-src 'self' data: blob: https:; font-src 'self' data: https://cdn.jsdelivr.net; media-src 'self' data: blob: https:; worker-src 'self' blob:; frame-src 'self' blob: http://127.0.0.1:* http://localhost:*; connect-src 'self' ipc: http://ipc.localhost http://127.0.0.1:* http://localhost:* ws://127.0.0.1:* ws://localhost:* https: wss:; object-src 'none'; base-uri 'self'; form-action 'self'"
},
"windows": [
{
"transparent": true,
"title": "Hanzo",
"width": 1280,
"height": 840,
"resizable": true,
"dragDropEnabled": false,
"titleBarStyle": "Overlay",
"hiddenTitle": true,
"create": false
},
{
"fullscreen": false,
"label": "spotlight",
"transparent": true,
"title": "Spotlight",
"width": 800,
"height": 490,
"resizable": true,
"dragDropEnabled": false,
"titleBarStyle": "Overlay",
"hiddenTitle": true,
"url": "src/windows/spotlight/index.html",
"center": true,
"skipTaskbar": true,
"shadow": true,
"decorations": false,
"visible": false,
"closable": false,
"parent": null,
"create": false
},
{
"fullscreen": false,
"label": "coordinator",
"transparent": true,
"title": "Coordinator",
"width": 720,
"height": 470,
"resizable": false,
"dragDropEnabled": false,
"titleBarStyle": "Overlay",
"hiddenTitle": true,
"url": "src/windows/coordinator/index.html",
"center": true,
"skipTaskbar": false,
"shadow": false,
"decorations": false,
"visible": false,
"closable": false,
"parent": null,
"create": false
},
{
"label": "hanzo-node-manager",
"url": "src/windows/hanzo-node-manager/index.html",
"transparent": true,
"title": "Hanzo Node Manager",
"width": 1280,
"height": 840,
"resizable": true,
"dragDropEnabled": false,
"titleBarStyle": "Overlay",
"hiddenTitle": true,
"create": false
}
],
"macOSPrivateApi": true
}
}