Skip to content

feat: support trusted API on separate network/IP/port#4717

Merged
robertsLando merged 8 commits into
masterfrom
feat/trusted-api-listener
Jul 17, 2026
Merged

feat: support trusted API on separate network/IP/port#4717
robertsLando merged 8 commits into
masterfrom
feat/trusted-api-listener

Conversation

@AlCalzone

Copy link
Copy Markdown
Member

This PR adds support for two environment variables that let a host application like Home Assistant establish a secure channel to Z-Wave JS UI's API, without interfering with the user's auth configuration.

This is done by specifying a network/IP/port on which a second API server is started, and an IP allowlist (which IPs may use this). The configuration works entirely through environment variables:

  • TRUSTED_API_LISTEN: Enables the trusted listener. Three forms are accepted:
    • An absolute path starting with /: bind a unix socket at that path. Access control is left to filesystem permissions. A stale socket file from an unclean shutdown is removed automatically on startup.
    • host:port with a literal IP (IPv6 in brackets, e.g. [fd00::1]:8092): bind exactly that address.
    • cidr:port (e.g. 172.30.32.0/23:8092): resolve the local interface address inside that network at startup and bind to it. This lets the host name a (docker) network without either side knowing the container's dynamic IP. Startup fails if no (or more than one) local address matches.
  • TRUSTED_API_ALLOWED_IPS: Comma-separated list of IPs/CIDRs (e.g. 172.30.32.2,127.0.0.1) allowed to connect to a TCP binding. Required for TCP bindings — startup fails without it. Ignored for unix sockets.

@AlCalzone
AlCalzone requested review from Copilot and robertsLando and removed request for Copilot July 3, 2026 12:38
@coveralls

coveralls commented Jul 3, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 29564759627

Warning

Build has drifted: This PR's base is out of sync with its target branch, so coverage data may include unrelated changes.
Quick fix: rebase this PR. Learn more →

Coverage increased (+4.4%) to 12.359%

Details

  • Coverage increased (+4.4%) from the base build.
  • Patch coverage: 35 uncovered changes across 4 files (172 of 207 lines covered, 83.09%).
  • No coverage regressions found.

Uncovered Changes

File Changed Covered %
api/lib/ipUtils.ts 83 61 73.49%
api/app.ts 13 7 53.85%
api/lib/trustedListener.ts 108 102 94.44%
api/lib/SocketManager.ts 3 2 66.67%

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 6763
Covered Lines: 900
Line Coverage: 13.31%
Relevant Branches: 4395
Covered Branches: 479
Branch Coverage: 10.9%
Branches in Coverage %: Yes
Coverage Strength: 2.15 hits per line

💛 - Coveralls

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an optional “trusted listener” that exposes the existing Express app on a second bind target (TCP or unix socket) intended for host applications (e.g., Home Assistant) to access Z-Wave JS UI APIs without user-auth, guarded by a TCP peer allowlist or filesystem permissions for unix sockets.

Changes:

  • Introduces trusted listener config parsing from TRUSTED_API_LISTEN / TRUSTED_API_ALLOWED_IPS, including CIDR-based bind-address resolution.
  • Adds a trusted listener HTTP server that marks allowlisted sockets as “trusted” and integrates it into auth + rate-limiting bypass paths.
  • Adds tests and documentation for the new environment variables; adds ipaddr.js dependency.

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
api/config/app.ts Adds trusted listener env var parsing + exported config/types.
api/lib/trustedListener.ts Implements trusted listener server, allowlist enforcement, and CIDR bind resolution.
api/lib/SocketManager.ts Adds helper to attach Socket.IO to an additional HTTP server.
api/app.ts Integrates trusted listener into startup, auth middleware, and rate limiting; closes listener on shutdown.
test/lib/trustedListenerConfig.test.ts Unit tests for trusted listener config parsing + helpers.
test/lib/trustedListener.test.ts Integration tests for trusted listener trust decisions (HTTP + Socket.IO + unix socket).
docs/guide/env-vars.md Documents trusted listener env vars and security model.
package.json Adds ipaddr.js.
package-lock.json Locks ipaddr.js and dependency tree updates.

Comment thread api/lib/trustedListener.ts
Comment thread api/lib/trustedListener.ts Outdated
Comment thread api/app.ts
Comment thread test/lib/trustedListener.test.ts
Comment thread test/lib/trustedListenerConfig.test.ts
Comment thread test/lib/trustedListenerConfig.test.ts
Comment thread docs/guide/env-vars.md Outdated
Comment thread api/config/app.ts Outdated
Comment thread api/lib/trustedListener.ts
Comment thread api/config/app.ts

@robertsLando robertsLando left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deep review — trusted API listener

Verdict: Ship with minor changes. The approach is sound and the security model holds up under scrutiny. Trust is decided on the kernel-reported TCP peer address in the connection event before any HTTP parsing, X-Forwarded-For/TRUST_PROXY are deliberately excluded, and the WeakSet<net.Socket> keyed on the raw socket cleanly covers keep-alive, HTTP/1.1 pipelining, and websocket-upgrade reuse. Verified fail-closed on remoteAddress === undefined, and the ::ffff: IPv4-mapped divergence between allowlist-parse and remote-match is fail-closed (no over-permit path). Backcompat on the main listener is clean — every new branch (isAuthenticated, /api/auth-enabled, the three rate-limiter skips) evaluates exactly as before.

Review run across 6 lenses (correctness, security, operability, design, tests, DRY). Findings below are robustness / hardening / test-coverage — none challenge the design.

Top 3 risks

  1. An error on the optional secondary listener hard-kills the primary gateway via process.exit(1), with divergent failure paths and thin diagnostics (flagged independently by 5 of 6 lenses).
  2. The unix socket is created with no explicit mode — under a permissive container umask it can be world-writable, i.e. unauthenticated full API control for any local process, despite the docs claiming access control is left to filesystem permissions.
  3. The core auth-bypass wiring in app.ts (isAuthenticated + rate-limit skip) is not integration-tested; only the underlying trust primitive is.

Strengths: correct threat model (raw peer address, headers excluded), the WeakSet abstraction reaching both HTTP and the socket.io handshake, fail-fast config validation, and strong helper/config-level test coverage.

Coverage: correctness, security, operability, design, tests, DRY. No changed file left uncovered; no Blockers surfaced by any lens.

Comment thread api/lib/trustedListener.ts
Comment thread api/lib/trustedListener.ts Outdated
Comment thread api/app.ts
Comment thread api/app.ts
Comment thread api/lib/trustedListener.ts
Comment thread api/lib/SocketManager.ts
Comment thread api/config/app.ts Outdated
Comment thread api/config/app.ts Outdated
Comment thread api/lib/trustedListener.ts Outdated
Comment thread api/lib/trustedListener.ts

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 9 changed files in this pull request and generated 6 comments.

Comment thread api/lib/trustedListener.ts Outdated
Comment thread api/lib/trustedListener.ts Outdated
Comment thread test/lib/trustedListenerConfig.test.ts
Comment thread test/lib/trustedListenerConfig.test.ts
Comment thread test/lib/trustedListener.test.ts
Comment thread test/lib/trustedAppIntegration.test.ts
AlCalzone and others added 3 commits July 7, 2026 15:36
…#4717 review)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@AlCalzone
AlCalzone requested a review from robertsLando July 8, 2026 13:53
robertsLando
robertsLando previously approved these changes Jul 16, 2026
Comment thread package-lock.json
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@robertsLando
robertsLando merged commit 25e522e into master Jul 17, 2026
13 checks passed
@robertsLando
robertsLando deleted the feat/trusted-api-listener branch July 17, 2026 08:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants