Expose authoring tools through an app-hosted HTTP server #16

Closed
opened 2026-09-16 12:05:36 +02:00 by morten-olsen · 2 comments
Owner

Context

Issue #10 delivered a transport-neutral authoring tool module. Regular users need desktop and network clients to reach it without developer mode, ADB, or port forwarding. The app therefore needs an explicitly enabled, LAN-wide HTTPS adapter. MCP remains outside the app: a desktop bridge can consume this HTTP contract and expose MCP to local agent clients.

Scope

  • Add an opt-in app-hosted HTTPS server over AuthoringToolModule.
  • Bind to the active LAN interface and advertise the dynamically selected port through Android NSD/DNS-SD so clients do not require an IP address or fixed port.
  • Reuse AuthoringToolRequest and AuthoringToolResponse exactly through one invocation endpoint; do not reproduce engine or registry behavior in routes.
  • On first activation, generate a cryptographically random static bearer token and a persistent TLS identity. Keep the token valid until the user regenerates it.
  • Provide a simple connection bundle for the desktop bridge containing discovery identity, bearer token, protocol version, and TLS certificate fingerprint. Never advertise the token through NSD.
  • Authenticate every authoring request, compare credentials safely, and let token regeneration revoke all existing clients immediately.
  • Expose start/stop, current reachability, network name/address, copy connection details, and regenerate-token actions in Settings.
  • Run only while an explicit foreground service and visible notification are active. Stopping or disabling must close the listener and unregister NSD immediately; do not silently start on boot.
  • Bound request/response sizes, concurrency, timeouts, and idle connections; serialize mutation dispatch through the shared authoring seam.
  • Record content-free credential fingerprint, tool, and outcome without workflow documents, fixtures, bearer tokens, or other secrets.
  • Account for Android local-network permission denial and revocation as platform versions require it; fail closed and expose an actionable Settings state.

Security model

  • LAN traffic is HTTPS only. Do not send a reusable bearer token or workflow contents over plaintext HTTP.
  • The desktop bridge pins the app-generated TLS identity from the user-provided connection bundle rather than trusting an unauthenticated certificate learned from the LAN.
  • NSD advertises only non-secret service identity, port, and protocol metadata.
  • The initial static token grants the complete authoring tool surface. Per-client identities and independently revocable scopes are deferred unless a demonstrated multi-client need justifies them.

Non-goals

  • Do not implement MCP semantics in the Android app.
  • Do not require developer mode, ADB, USB, or port forwarding.
  • Do not expose production execution, arbitrary code, raw databases, plaintext LAN authoring, or unauthenticated LAN access.
  • Do not depend on proprietary push or discovery services.

Acceptance

  • A regular user can enable the server and connect a desktop bridge from the same LAN using only in-app connection details.
  • The bridge discovers the phone through NSD, authenticates with the static token, pins the expected TLS identity, and can discover tools, inspect definitions, perform a validated mutation, and run a deterministic fixture test.
  • Unauthenticated, wrong-token, revoked-token, wrong-certificate, oversized, malformed, and concurrent mutation requests fail distinctly without unintended engine mutation.
  • Regenerating the token immediately invalidates the previous connection bundle.
  • Stopping or disabling the server closes LAN reachability, unregisters discovery, and releases foreground/background ownership.
  • Network loss, address changes, local-network permission denial/revocation, and NSD registration failure are reflected accurately in Settings.
  • The HTTP adapter remains thin and contract-compatible with #10, and a desktop MCP adapter requires no additional Android endpoints.
  • Focused integration tests cover TLS pinning, token lifecycle, discovery metadata, one end-to-end mutation, network loss, and shutdown.
## Context Issue #10 delivered a transport-neutral authoring tool module. Regular users need desktop and network clients to reach it without developer mode, ADB, or port forwarding. The app therefore needs an explicitly enabled, LAN-wide HTTPS adapter. MCP remains outside the app: a desktop bridge can consume this HTTP contract and expose MCP to local agent clients. ## Scope - Add an opt-in app-hosted HTTPS server over `AuthoringToolModule`. - Bind to the active LAN interface and advertise the dynamically selected port through Android NSD/DNS-SD so clients do not require an IP address or fixed port. - Reuse `AuthoringToolRequest` and `AuthoringToolResponse` exactly through one invocation endpoint; do not reproduce engine or registry behavior in routes. - On first activation, generate a cryptographically random static bearer token and a persistent TLS identity. Keep the token valid until the user regenerates it. - Provide a simple connection bundle for the desktop bridge containing discovery identity, bearer token, protocol version, and TLS certificate fingerprint. Never advertise the token through NSD. - Authenticate every authoring request, compare credentials safely, and let token regeneration revoke all existing clients immediately. - Expose start/stop, current reachability, network name/address, copy connection details, and regenerate-token actions in Settings. - Run only while an explicit foreground service and visible notification are active. Stopping or disabling must close the listener and unregister NSD immediately; do not silently start on boot. - Bound request/response sizes, concurrency, timeouts, and idle connections; serialize mutation dispatch through the shared authoring seam. - Record content-free credential fingerprint, tool, and outcome without workflow documents, fixtures, bearer tokens, or other secrets. - Account for Android local-network permission denial and revocation as platform versions require it; fail closed and expose an actionable Settings state. ## Security model - LAN traffic is HTTPS only. Do not send a reusable bearer token or workflow contents over plaintext HTTP. - The desktop bridge pins the app-generated TLS identity from the user-provided connection bundle rather than trusting an unauthenticated certificate learned from the LAN. - NSD advertises only non-secret service identity, port, and protocol metadata. - The initial static token grants the complete authoring tool surface. Per-client identities and independently revocable scopes are deferred unless a demonstrated multi-client need justifies them. ## Non-goals - Do not implement MCP semantics in the Android app. - Do not require developer mode, ADB, USB, or port forwarding. - Do not expose production execution, arbitrary code, raw databases, plaintext LAN authoring, or unauthenticated LAN access. - Do not depend on proprietary push or discovery services. ## Acceptance - A regular user can enable the server and connect a desktop bridge from the same LAN using only in-app connection details. - The bridge discovers the phone through NSD, authenticates with the static token, pins the expected TLS identity, and can discover tools, inspect definitions, perform a validated mutation, and run a deterministic fixture test. - Unauthenticated, wrong-token, revoked-token, wrong-certificate, oversized, malformed, and concurrent mutation requests fail distinctly without unintended engine mutation. - Regenerating the token immediately invalidates the previous connection bundle. - Stopping or disabling the server closes LAN reachability, unregisters discovery, and releases foreground/background ownership. - Network loss, address changes, local-network permission denial/revocation, and NSD registration failure are reflected accurately in Settings. - The HTTP adapter remains thin and contract-compatible with #10, and a desktop MCP adapter requires no additional Android endpoints. - Focused integration tests cover TLS pinning, token lifecycle, discovery metadata, one end-to-end mutation, network loss, and shutdown.
Author
Owner

Implemented and pushed in 0d0e162.

Delivered:

  • Explicitly enabled LAN-wide HTTPS authoring server in a connected-device foreground service; no boot autostart.
  • Persistent self-signed TLS identity with certificate pinning and encrypted-at-rest private key material.
  • Static derived bearer token with in-app regeneration and connection-bundle copy flow.
  • Android NSD advertisement using _https._tcp. without exposing the token.
  • Bounded HTTP/1.1 transport at POST /v1/invoke using the existing authoring tool protocol, limits, serialized mutations, and audit attribution.
  • Settings status for startup, network availability, running address, errors, TLS fingerprint, and immediate shutdown.
  • Unit and on-device integration coverage for auth, pinning, workflow mutation, token rotation, request bounds, and shutdown.

Verified:

  • ./gradlew :app:connectedDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=cloud.olsen.macros.platform.LanAuthoringHttpServerTest
  • Manual emulator scenario: service reached Running, transitioned to Waiting for Wi-Fi or Ethernet when Wi-Fi was disabled, and returned to Running after recovery.
  • task ci:quality
Implemented and pushed in 0d0e162. Delivered: - Explicitly enabled LAN-wide HTTPS authoring server in a connected-device foreground service; no boot autostart. - Persistent self-signed TLS identity with certificate pinning and encrypted-at-rest private key material. - Static derived bearer token with in-app regeneration and connection-bundle copy flow. - Android NSD advertisement using `_https._tcp.` without exposing the token. - Bounded HTTP/1.1 transport at `POST /v1/invoke` using the existing authoring tool protocol, limits, serialized mutations, and audit attribution. - Settings status for startup, network availability, running address, errors, TLS fingerprint, and immediate shutdown. - Unit and on-device integration coverage for auth, pinning, workflow mutation, token rotation, request bounds, and shutdown. Verified: - `./gradlew :app:connectedDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=cloud.olsen.macros.platform.LanAuthoringHttpServerTest` - Manual emulator scenario: service reached Running, transitioned to Waiting for Wi-Fi or Ethernet when Wi-Fi was disabled, and returned to Running after recovery. - `task ci:quality`
Author
Owner

Follow-up fix pushed in 5f2c3cd.

Token regeneration now completes synchronously, immediately revokes the prior token without restarting the HTTPS listener, copies the new token directly to the clipboard, and reports that it was copied. The Authoring settings card also has a dedicated Copy access token action, so manual HTTP/cURL clients no longer need to parse the JSON connection bundle.

Verified with the actual Compose UI, the on-device LAN HTTPS/token-rotation integration test, and task ci:quality.

Follow-up fix pushed in `5f2c3cd`. Token regeneration now completes synchronously, immediately revokes the prior token without restarting the HTTPS listener, copies the new token directly to the clipboard, and reports that it was copied. The Authoring settings card also has a dedicated **Copy access token** action, so manual HTTP/cURL clients no longer need to parse the JSON connection bundle. Verified with the actual Compose UI, the on-device LAN HTTPS/token-rotation integration test, and `task ci:quality`.
Sign in to join this conversation.
No labels
bug
enhancement
feature
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
incubator/macros#16
No description provided.