Skip to content

Route client-side RA cloud requests through router /cloud proxy on local builds (CORS fix) #1179

Description

@AustinChangLinksys

Problem

When the PrivacyGUI web app is served from the router itself (local build), the browser origin is the router's LAN IP. Client-side Remote Assistance (RA) requests that hit the cloud host directly are blocked by CORS. This is a confirmed, current-production problem.

1.x solved this by injecting a getHost closure into LinksysHttpClient (via the removed cloudRepositoryProvider) so client requests went through the router's /cloud/ reverse proxy (same-origin). That path is dead in 2.x: LinksysHttpClient.getHost / combineUrl still exist but combineUrl is never called, and every caller builds an absolute cloud URL itself, bypassing getHost.

Scope

RA only. Client-side RA requests proxy through the router on local builds; CA-side requests always go direct to cloud (the CA portal is cloud-hosted — proxying would misroute it). Firmware OTA and geolocation are explicitly out of scope.

Proposed solution

Add a small, testable host-resolution layer instead of restoring the dead getHost path:

  • kProxyPrefix constant (/cloud) — single point of change once FW confirms the prefix.
  • CloudHostResolver — decides the URL base to prepend to a Guardian endpoint:
    • CA-side → always direct cloud base.
    • Client-side → router proxy base (<origin>/cloud) iff local build AND origin resolvable; otherwise direct cloud (safe fallback).
  • Inject the resolver into GuardianApiClient and thread forCA through _buildUrl / _request, derived from sessionToken != null so it stays in lock-step with the auth-header branch (no drift possible).
  • Host source = Uri.base.origin (scheme + host + port). Chosen over window.location.host because same-origin/CORS requires the scheme to match; Uri.base.origin preserves it and is already an established pattern in this repo.

Acceptance Criteria

  • On a local build (BuildConfig.isLocal() == true), client-side RA requests (fetchDeviceToken, getSessions, getSessionInfo, createPin, deleteSession) target <Uri.base.origin>/cloud/v1/guardians/....
  • CA-side requests (getSessionInfoForCA, deleteSessionForCA) always target the cloud host directly, even on a local build.
  • On a non-local build, every RA request (client + CA) targets the cloud host directly — behavior byte-for-byte identical to today.
  • When the origin is unresolvable (empty), client-side requests fall back to the cloud host rather than failing.
  • Uri.base.origin scheme is preserved (http stays http, port preserved) — no forced https://.
  • The proxy path prefix is a single configurable constant (kProxyPrefix); changing the FW prefix requires no other code change.
  • Existing RA flows (dialog, banner, CA confirm view) work unchanged; remote_assistance_service_test.dart stays green.

Blocked / open items

  • FW proxy prefix unconfirmedkProxyPrefix is one constant; flip the value when FW lands. This blocks on-device sign-off, not implementation. (label: need-fw-confirm)
  • E2E mock builds are local (isLocal() == true) → client RA calls take the proxy path; if the E2E harness mocks Guardian at the network boundary, confirm it intercepts /cloud/... URLs too.

Tests

  • test/core/cloud/cloud_host_resolver_test.dart — resolver logic (7 cases: local+client, local+CA, empty-origin fallback, non-local, port preserved, http scheme preserved, default constructor).
  • test/core/cloud/guardian_api_client_test.dart — URL assembly (client methods → proxy URL incl. session-id substitution; CA methods → cloud URL under the same resolver).
  • test/core/cloud/services/remote_assistance_service_test.dart — regression, stays green unchanged.

Metadata

Metadata

Assignees

No one assigned

    Labels

    2.xLabeled for 2.x versionenhancementNew feature or requestfeature:remoteRemote assistance related issuesneed-fw-confirmRoot cause needs firmware-team confirmation before dev

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions