Skip to content

[LSWF] EOL models: full block (local + setup) #1176

Description

@AustinChangLinksys

Background

As part of the cloud service sunset, we need a list of completely EOL SKUs/models that are fully unsupported — the app should not be usable for them (both local access and setup). This is separate from the whitelist work (#1162 remote access / #1163 local-only setup) — EOL blocking is stricter, touches different interception points, and is its own chunk of work.

The code lives in the internal git.lswf.net symmetry-mobile repo. This issue is in the requirements-clarification stage — several points pending confirmation, not started.
Jimmy's words: "a list of SKU/models that are completely EOL... don't allow local access or remote access."

Scope (simplified)

Remote/cloud is already gated by the whitelist (#1162) — only whitelisted models can use cloud, and an EOL model is by definition not on the whitelist, so cloud is already off for it. Therefore EOL only needs to add gating in two places: local access + setup, without touching the cloud/remote logic again.

Whitelist (#1162/#1163) EOL (this issue)
Governs cloud/remote + setup routing local access + setup
cloud governed by whitelist not touched (whitelist already blocks it)

To avoid depending on list-data consistency, the implementation will treat an EOL hit as an absolute block (including cloud for that device) — EOL check has the highest priority.

Goal

For the target device currently being managed / set up, if its SKU is on the EOL list → block entirely (local + setup) and show a "device no longer supported" screen. The block is bound to "managing this device," not "the user being connected to its WiFi" (respecting connected ≠ managed, so we don't wrongly block someone remotely managing a different, valid device).

Technical finding: when/how the model number is obtained (prerequisite for interception)

Implementing EOL requires the model number. From the code investigation:

  • mDNS/zeroconf does NOT carry the model — the discovery TXT record only has IP/name/type (discoveredRouters.js:248-262). "Block on sight during scan" is not possible.
  • Must use JNAP: after connecting to the device, send /core/GetDeviceInfo (discoveredRouters.js:424-436); BLE setup uses /nodes/setup/GetVersionInfo (scanMachine.js:712-730); child nodes use GetDiscoveredUnconfiguredWirelessNodes. All are cloud-independent, which fits EOL's "govern local" positioning.

Interception point: bind to the "model-write convergence point," not a single state

  • Setup has 4 entry types (from the idle state): DISCOVER (native/iOS auto), START (active add / after login), CHILD (add node from dashboard), LEGACY.
  • The common convergence point directSetupFlow (setupMachine.js:1051) is on almost every path, but the model isn't necessarily obtained yet at that point (the START path doesn't go through discover first). "Having the model" and "on every entry path" are two different points.
  • Conclusion: the EOL check should bind to the action where the model number is written into context.device — primarily setProductConfigFromModelNumber (setupMachine.js:272, called after the model is written), with the BLE path covered by setVersionInfo (scanMachine.js:1290). The exact interception action to be finalized during implementation.

UX: the only viable path is "app opens → detects → 'no longer supported' screen"

Jimmy raised "should the app refuse to open at all, or show a 'device no longer supported' screen?" Technically "refuse to open at all" is not feasible — the model number can only be obtained after connecting to the device via JNAP, so the app cannot decide EOL at the very moment of launch; it must open, connect, and obtain the model first before it can judge.

So the only viable path is: app opens → detects EOL → stops on a "device no longer supported" terminal screen. What's pending from Jimmy is the wording and exits of that screen (log out should be kept; whether to add a contact-support / device-replacement guide).

Task breakdown (to be refined)

  • EOL list loading (source TBD) + cache (fail-open)
  • SKU match check (model obtained locally via JNAP, not mDNS)
  • Interception: add the EOL check at the model-write convergence action (setProductConfigFromModelNumber + BLE setVersionInfo; details TBD)
  • Block local login / local access to an EOL device
  • Block setup of an EOL device (after model is obtained, before showing any setup UI)
  • "Device no longer supported" terminal screen + log-out exit (wording pending from Jimmy/PM)

Pending confirmation

  • Wording & exits of the "no longer supported" screen: keep log out; add contact-support / replacement guidance? ("refuse to open" is ruled out — see above)
  • Block granularity: bound to "managing this EOL device," or "block whenever connected to an EOL router"? (leaning toward the former, pending Jimmy)
  • Mesh mixed case: when a parent/child node is EOL, block the whole set or only that node?
  • List source/format: a separate column in the same txt as the whitelist, or a separate file?
  • Fail policy: confirm fail-open (allow when the list can't be fetched, to avoid locking out all users).

Effort estimate (initial)

Because this is a Cordova hybrid app, the bulk of the logic lives in the shared JS (SFW) layer, which covers both platforms at once. Android in particular attaches to the JS layer — its native shell is thin (Cordova standard events; window.Bridge is null on Android), so blocking in JS effectively blocks Android with no extra native work. iOS may need additional native work because its native shell participates more in the login/setup entry points.

Area Estimate Notes
JS shared layer (list load + cache/fail-open, SKU match, setup interception, local-access block, "no longer supported" screen) — covers Android ~4.5d Reuses the whitelist remoteAccessWhitelist module heavily
Android verification ~0.5d Env ready; verify the JS-layer block takes effect
iOS native (login/setup native-entry interception) ~3–4d No longer blocked#1160 restored iOS buildability + on-device signing
iOS verification (physical device) ~1d Signing unblocked via #1160
Integration + edge cases (mesh mixed, list-update eviction) ~1–2d
Total ~10–13d (≈ 2–2.5 weeks)

Could shrink: the iOS ~3–4d is a conservative upper bound assuming the iOS native login/setup entries need native-side interception. If it turns out iOS also hands control fully to the WebView (like Android), the JS layer alone suffices and the whole thing drops to ~1 week (pure JS + verification on both platforms). With #1160 done, iOS is now buildable, so this can be verified up front.

Note: version/branch baseline TBD (#1160 mentioned a 4.0.0 alignment); this estimate is independent of which baseline we land on.

Current status

Requirements detailed, interception path clarified (via JNAP, bound to the model-write convergence point, UX limited to the "no longer supported" screen). Not started — implementation pending the confirmations above. Adds development time beyond #1162/#1163.

Metadata

Metadata

Assignees

Labels

PlanUnder planninglswf-mobilelegacy mobile app label

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions