Skip to content

feat: Remote Assistance Implementation & Theme Studio Fixes#608

Merged
AustinChangLinksys merged 32 commits intodev-2.0.0from
peter/remote_assistance
Feb 3, 2026
Merged

feat: Remote Assistance Implementation & Theme Studio Fixes#608
AustinChangLinksys merged 32 commits intodev-2.0.0from
peter/remote_assistance

Conversation

@PeterJhongLinksys
Copy link
Collaborator

@PeterJhongLinksys PeterJhongLinksys commented Jan 28, 2026

User description

Summary

This PR merges the Remote Assistance feature set and a fix for the Theme Studio export dialog into dev-2.0.0.

Changes

  • Remote Assistance:
    • Implemented read-only mode checks for critical settings (IPv4/IPv6, DHCP).
    • Added safe operations whitelist (LED, Speed Test, Ping, Traceroute).
    • Replaced immediate switches with RemoteAwareSwitch.
    • Added translations for remote mode restrictions.
  • Theme Studio:
    • Fixed 'Export Configuration' dialog overflow by making content scrollable and moving buttons to actions.
  • Documentation:
    • Added verification reports and usage guides.

PR Type

Enhancement, Bug fix, Tests, Documentation


Description

  • Remote Assistance Feature Implementation: Comprehensive implementation of remote read-only mode protection across the UI layer

    • Created RemoteAccessProvider and RemoteAccessState for centralized remote mode state management
    • Implemented RemoteAwareSwitch component that automatically disables switches in remote mode while preserving their values
    • Added defensive checks in RouterRepository to block write operations (SET, transactions) while allowing safe read-only operations (LED, Speed Test, Ping, Traceroute)
    • Enhanced UiKitPageView with checkRemoteReadOnly parameter to auto-disable Save buttons in remote mode
    • Created RemoteReadOnlyBanner informational widget displayed at top of app when in remote mode
  • UI Controls Protection: Replaced 10 immediate-mode AppSwitch instances with RemoteAwareSwitch across dashboard, WiFi, VPN, privacy, and topology views

  • Critical Settings Protection: Added remote read-only checks and disabled edit buttons for IPv4/IPv6 connection settings, device/node name editing, and IP address reservation

  • Theme Studio Bug Fix: Fixed export configuration dialog overflow by making content scrollable and moving action buttons to dialog actions parameter

  • Comprehensive Localization: Added remoteViewModeActive translations for 27 languages (English, Spanish, French, German, Chinese, Japanese, Korean, Arabic, Russian, and others)

  • Documentation & Verification: Created implementation plan, design document, usage guide, switch replacement catalog, and verification report confirming 2756 tests passing with 100% success rate


Diagram Walkthrough

flowchart LR
  A["Remote Mode Detection<br/>remoteAccessProvider"] --> B["RemoteAwareSwitch<br/>Auto-disable in remote"]
  A --> C["RouterRepository<br/>Block write operations"]
  A --> D["UiKitPageView<br/>Auto-disable Save button"]
  A --> E["RemoteReadOnlyBanner<br/>Info widget"]
  B --> F["Dashboard Switches<br/>WiFi, Privacy, LED"]
  B --> G["Settings Switches<br/>DHCP, VPN"]
  C --> H["Safe Operations<br/>LED, Speed Test, Ping"]
  D --> I["Form-based Settings<br/>IPv4, IPv6, Network"]
  E --> J["27 Language<br/>Translations"]
  K["Theme Studio<br/>Export Dialog Fix"] -.-> L["Scrollable Content<br/>Better Layout"]
Loading

File Walkthrough

Relevant files
Tests
5 files
router_repository_test.dart
RouterRepository remote read-only mode defensive tests     

test/core/jnap/router_repository_test.dart

  • Added comprehensive test suite for RouterRepository defensive checks
    in remote read-only mode
  • Tests verify that SET operations are blocked while GET operations are
    allowed
  • Tests validate transaction handling with write operation detection
  • Tests confirm safe operations (LED, speed test, ping, traceroute) are
    permitted in remote mode
+617/-0 
remote_aware_switch_test.dart
RemoteAwareSwitch widget tests                                                     

test/page/components/views/remote_aware_switch_test.dart

  • Created widget tests for RemoteAwareSwitch component
  • Tests verify switch is enabled in local mode and disabled in remote
    mode
  • Tests confirm switch value displays correctly when disabled
  • Tests validate reactive state updates when loginType changes
+201/-0 
remote_access_provider_test.dart
RemoteAccessProvider state tests                                                 

test/providers/remote_access/remote_access_provider_test.dart

  • Added tests verifying remoteAccessProvider returns correct
    isRemoteReadOnly state
  • Tests cover local, remote, and none login types
  • Tests validate compile-time forced remote mode via
    BuildConfig.forceCommandType
  • Tests handle auth provider loading and error states gracefully
+151/-0 
remote_access_state_test.dart
RemoteAccessState serialization and equality tests             

test/providers/remote_access/remote_access_state_test.dart

  • Added tests for RemoteAccessState instantiation and properties
  • Tests verify serialization/deserialization (toMap/fromMap,
    toJson/fromJson)
  • Tests validate equality and hash code implementation
  • Tests confirm copyWith method creates new instances correctly
+103/-0 
remote_read_only_banner_test.dart
RemoteReadOnlyBanner widget tests                                               

test/page/components/views/remote_read_only_banner_test.dart

  • Added widget tests for RemoteReadOnlyBanner component
  • Tests verify banner displays when isRemoteReadOnly is true
  • Tests confirm banner hides when isRemoteReadOnly is false
  • Tests validate banner styling and theme color usage
+97/-0   
Enhancement
23 files
instant_admin_view.dart
Instant admin view remote access integration                         

lib/page/instant_admin/views/instant_admin_view.dart

  • Replaced BuildConfig.isRemote() with remoteAccessProvider for dynamic
    remote mode detection
  • Added tooltip and disabled state to password edit button in remote
    mode
  • Replaced AppSwitch with RemoteAwareSwitch for DHCP toggle
  • Updated manual firmware update button to use provider-based remote
    check
+29/-15 
router_repository.dart
RouterRepository defensive checks for remote mode               

lib/core/jnap/router_repository.dart

  • Added _isReadOnlyOperation() method to identify safe read-only JNAP
    actions
  • Added _isRemoteReadOnly() method to check remote read-only mode status
  • Implemented defensive checks in send() to block write operations in
    remote mode
  • Implemented defensive checks in transaction() to block transactions
    with write operations
+64/-0   
ipv6_connection_view.dart
IPv6 connection view remote access integration                     

lib/page/advanced_settings/internet_settings/views/ipv6_connection_view.dart

  • Converted from StatelessWidget to ConsumerWidget for provider access
  • Replaced BuildConfig.isRemote() with remoteAccessProvider watch
  • Added tooltip and disabled state to edit button in remote mode
  • Updated method signatures to pass WidgetRef for provider access
+15/-11 
ipv4_connection_view.dart
IPv4 connection view remote access integration                     

lib/page/advanced_settings/internet_settings/views/ipv4_connection_view.dart

  • Converted from StatelessWidget to ConsumerWidget for provider access
  • Replaced BuildConfig.isRemote() with remoteAccessProvider watch
  • Added tooltip and disabled state to edit button in remote mode
  • Updated method signatures to pass WidgetRef for provider access
+15/-11 
topology_menu_helper.dart
Topology menu helper remote mode restrictions                       

lib/page/instant_topology/helpers/topology_menu_helper.dart

  • Added WidgetRef parameter to buildNodeMenu() method
  • Added remote read-only mode check for menu items
  • Disabled reboot, pairing, and factory reset menu items in remote mode
  • Kept LED blinking enabled as safe operation in remote mode
+15/-4   
device_detail_view.dart
Device detail view remote access restrictions                       

lib/page/instant_device/views/device_detail_view.dart

  • Added remote read-only check to device name edit button
  • Added tooltip showing feature unavailable message in remote mode
  • Disabled edit button when in remote mode
  • Added remote check to IP address reserve button visibility
+17/-4   
local_network_settings_view.dart
Local network settings remote access provider integration

lib/page/advanced_settings/local_network_settings/views/local_network_settings_view.dart

  • Replaced BuildConfig.isRemote() with remoteAccessProvider for dynamic
    checks
  • Updated IP redirection logic to use provider-based remote mode
    detection
  • Removed static build config dependency in favor of reactive provider
+7/-4     
ui_kit_page_view.dart
UiKitPageView auto-disable Save button in remote mode       

lib/page/components/ui_kit_page_view.dart

  • Added checkRemoteReadOnly parameter to UiKitBottomBarConfig (defaults
    to true)
  • Added remote read-only check in _buildBottomBarConfig() method
  • Auto-disables positive button when in remote mode and
    checkRemoteReadOnly is true
  • Added import for remoteAccessProvider
+10/-1   
release_and_renew_view.dart
Release and renew view remote access restrictions               

lib/page/advanced_settings/internet_settings/views/release_and_renew_view.dart

  • Added remote read-only check to IPv4 release/renew button
  • Added remote read-only check to IPv6 release/renew button
  • Disabled buttons when in remote mode
+7/-2     
port_and_speed.dart
Port and speed dashboard widget remote access integration

lib/page/dashboard/views/components/widgets/composite/port_and_speed.dart

  • Replaced BuildConfig.isRemote() with remoteAccessProvider watch
  • Updated speed test widget opacity and interaction based on provider
    state
  • Removed static build config dependency
+6/-4     
instant_verify_view.dart
Instant verify view remote access provider integration     

lib/page/instant_verify/views/instant_verify_view.dart

  • Replaced BuildConfig.isRemote() with remoteAccessProvider watch
  • Updated speed test widget opacity and interaction based on provider
    state
  • Modified node menu builder to pass ref parameter for remote checks
  • Removed static build config dependency
+8/-4     
remote_access_state.dart
RemoteAccessState immutable state class                                   

lib/providers/remote_access/remote_access_state.dart

  • Created immutable RemoteAccessState class with isRemoteReadOnly
    property
  • Implemented serialization methods (toMap, fromMap, toJson, fromJson)
  • Implemented copyWith for state updates
  • Implemented Equatable for equality comparison
+54/-0   
quick_panel.dart
Quick panel dashboard switches remote aware                           

lib/page/dashboard/views/components/widgets/composite/quick_panel.dart

  • Replaced AppSwitch with RemoteAwareSwitch for WiFi toggle
  • Replaced AppSwitch with RemoteAwareSwitch for privacy mode toggle
  • Replaced AppSwitch with RemoteAwareSwitch for node light toggle
+4/-3     
remote_read_only_banner.dart
RemoteReadOnlyBanner informational widget                               

lib/page/components/views/remote_read_only_banner.dart

  • Created banner widget that displays when in remote read-only mode
  • Shows shield icon and informational message about disabled settings
  • Uses theme colors for consistent styling
  • Hides when not in remote mode
+59/-0   
node_detail_view.dart
Node detail view remote access restrictions                           

lib/page/nodes/views/node_detail_view.dart

  • Added remote read-only check to node name edit button
  • Added tooltip showing feature unavailable message in remote mode
  • Disabled edit button when in remote mode
+16/-5   
root_container.dart
Root container remote banner integration                                 

lib/page/components/layouts/root_container.dart

  • Restructured layout from Stack to Column with SafeArea
  • Added RemoteReadOnlyBanner at top of layout
  • Wrapped main content in Expanded Stack for proper layout
  • Banner respects safe area and displays above all content
+18/-4   
remote_access_provider.dart
RemoteAccessProvider state management                                       

lib/providers/remote_access/remote_access_provider.dart

  • Created provider that determines remote read-only mode status
  • Watches authProvider for login type changes
  • Checks BuildConfig.forceCommandType for compile-time forced remote
    mode
  • Returns RemoteAccessState with isRemoteReadOnly flag
+30/-0   
remote_aware_switch.dart
RemoteAwareSwitch auto-disabling component                             

lib/page/components/views/remote_aware_switch.dart

  • Created RemoteAwareSwitch wrapper component for AppSwitch
  • Automatically disables switch in remote read-only mode
  • Watches remoteAccessProvider for state changes
  • Preserves switch value while disabling interaction
+39/-0   
instant_privacy_view.dart
Instant privacy view switch remote aware                                 

lib/page/instant_privacy/views/instant_privacy_view.dart

  • Replaced AppSwitch with RemoteAwareSwitch for instant privacy toggle
+2/-1     
wifi_card.dart
WiFi card switch remote aware                                                       

lib/page/dashboard/views/components/widgets/parts/wifi_card.dart

  • Replaced AppSwitch with RemoteAwareSwitch for WiFi enable/disable
    toggle
+2/-1     
vpn_status_tile.dart
VPN status tile switch remote aware                                           

lib/page/vpn/views/vpn_status_tile.dart

  • Replaced AppSwitch with RemoteAwareSwitch for VPN enable/disable
    toggle
+2/-1     
geolocation_provider.dart
Geolocation provider master device lookup refactor             

lib/core/cloud/providers/geolocation/geolocation_provider.dart

  • Refactored master device lookup to use isMaster property instead of
    checking nodeType
  • Improved code readability by extracting nodeDevices to variable
+2/-4     
instant_topology_view.dart
Instant topology view menu builder ref parameter                 

lib/page/instant_topology/views/instant_topology_view.dart

  • Updated node menu builder callback to pass ref parameter
  • Enables remote access checks in topology menu items
+2/-1     
Bug fix
1 files
theme_studio_panel.dart
Theme Studio export dialog overflow fix                                   

lib/demo/theme_studio/theme_studio_panel.dart

  • Fixed export configuration dialog overflow by wrapping content in
    SingleChildScrollView
  • Moved action buttons from content to dialog actions parameter
  • Improved dialog layout for better scrolling behavior
+28/-35 
Documentation
6 files
2026-01-26-remote-ui-controls-implementation.md
Remote UI controls implementation plan documentation         

docs/plans/2026-01-26-remote-ui-controls-implementation.md

  • Created comprehensive implementation plan for remote UI controls
    protection
  • Detailed 12-task breakdown with step-by-step instructions
  • Includes test-driven development approach and verification procedures
  • Documents success criteria and estimated effort
+934/-0 
2026-01-20-remote-read-only-mode-usage.md
Remote read-only mode usage guide and Thai localization   

docs/plans/2026-01-20-remote-read-only-mode-usage.md

  • Added Thai translation for remote view mode active banner message
+303/-0 
app_th.arb
Thai localization for remote view mode banner                       

lib/l10n/app_th.arb

  • Added Thai translation for remoteViewModeActive message
+1/-0     
2026-01-26-remote-ui-controls-design.md
Remote UI Controls Protection Design Document                       

docs/plans/2026-01-26-remote-ui-controls-design.md

  • Comprehensive design document for extending remote read-only mode
    protection to UI layer
  • Defines two operation modes: immediate effect (direct JNAP operations)
    and form mode (deferred save)
  • Specifies RemoteAwareSwitch component for wrapping switches that
    trigger immediate JNAP operations
  • Details UiKitBottomBarConfig enhancement with checkRemoteReadOnly
    parameter to auto-disable Save buttons
  • Includes implementation strategy, testing strategy, edge cases, and
    migration guide
+452/-0 
2026-01-26-switch-replacement-catalog.md
AppSwitch Usage Analysis and Replacement Catalog                 

docs/plans/2026-01-26-switch-replacement-catalog.md

  • Catalogs all 21 AppSwitch usages across the codebase
  • Categorizes switches into three groups: IMMEDIATE mode (12 switches
    requiring replacement), FORM mode (13 auto-protected), and UI-only (4
    no action needed)
  • Provides detailed analysis for each switch including file location,
    purpose, JNAP impact, and recommended action
  • Identifies implementation priority with high-priority immediate mode
    switches
+222/-0 
2026-01-26-remote-ui-controls-verification.md
Remote UI Controls Implementation Verification Report       

docs/verification/2026-01-26-remote-ui-controls-verification.md

  • Verification report confirming successful implementation of UI
    controls protection
  • Documents creation of RemoteAwareSwitch component and
    UiKitBottomBarConfig enhancement
  • Lists 10 immediate-mode switches replaced and 13 form Save buttons
    auto-protected
  • Reports 2756 tests passing with 100% success rate and no regressions
  • Includes manual testing checklist and documentation updates
+213/-0 
Localization
25 files
app_el.arb
Greek Localization for Remote View Mode Banner                     

lib/l10n/app_el.arb

  • Adds Greek translation for remoteViewModeActive key: "Λειτουργία
    απομακρυσμένης προβολής - Οι αλλαγές ρυθμίσεων είναι
    απενεργοποιημένες"
+1/-0     
app_ja.arb
Japanese Localization for Remote View Mode Banner               

lib/l10n/app_ja.arb

  • Adds Japanese translation for remoteViewModeActive key: "リモート表示モード -
    設定変更は無効になっています"
+1/-0     
app_pl.arb
Polish Localization for Remote View Mode Banner                   

lib/l10n/app_pl.arb

  • Adds Polish translation for remoteViewModeActive key: "Tryb zdalnego
    wyświetlania - Zmiany ustawień są wyłączone"
+1/-0     
app_tr.arb
Turkish Localization for Remote View Mode Banner                 

lib/l10n/app_tr.arb

  • Adds Turkish translation for remoteViewModeActive key: "Uzaktan
    Görüntüleme Modu - Ayar değişiklikleri devre dışı"
+1/-0     
app_vi.arb
Vietnamese Localization for Remote View Mode Banner           

lib/l10n/app_vi.arb

  • Adds Vietnamese translation for remoteViewModeActive key: "Chế độ xem
    từ xa - Thay đổi cài đặt bị vô hiệu hóa"
+1/-0     
app_fi.arb
Finnish Localization for Remote View Mode Banner                 

lib/l10n/app_fi.arb

  • Adds Finnish translation for remoteViewModeActive key: "Etäkatselutila
    - Asetusten muuttaminen on poistettu käytöstä"
+1/-0     
app_ar.arb
Arabic Localization for Remote View Mode Banner                   

lib/l10n/app_ar.arb

  • Adds Arabic translation for remoteViewModeActive key: "وضع العرض عن
    بُعد - تغييرات الإعدادات معطلة"
+1/-0     
app_ko.arb
Korean Localization for Remote View Mode Banner                   

lib/l10n/app_ko.arb

  • Adds Korean translation for remoteViewModeActive key: "원격 보기 모드 - 설정
    변경이 비활성화되었습니다"
+1/-0     
app_fr_ca.arb
Canadian French Localization for Remote View Mode Banner 

lib/l10n/app_fr_ca.arb

  • Adds Canadian French translation for remoteViewModeActive key: "Mode
    affichage à distance - Les modifications de paramètres sont
    désactivées"
+1/-0     
app_zh_TW.arb
Traditional Chinese Localization for Remote View Mode Banner

lib/l10n/app_zh_TW.arb

  • Adds Traditional Chinese translation for remoteViewModeActive key:
    "遠端檢視模式 - 無法修改設定"
+1/-0     
app_ru.arb
Russian Localization for Remote View Mode Banner                 

lib/l10n/app_ru.arb

  • Adds Russian translation for remoteViewModeActive key: "Режим
    удаленного просмотра - Изменение настроек отключено"
+1/-0     
app_sv.arb
Swedish Localization for Remote View Mode Banner                 

lib/l10n/app_sv.arb

  • Adds Swedish translation for remoteViewModeActive key:
    "Fjärrvisningsläge - Inställningsändringar är inaktiverade"
+1/-0     
app_da.arb
Danish Localization for Remote View Mode Banner                   

lib/l10n/app_da.arb

  • Adds Danish translation for remoteViewModeActive key: "Fjernsyn
    tilstand - Indstillingsændringer er deaktiveret"
+1/-0     
app_pt_pt.arb
European Portuguese Localization for Remote View Mode Banner

lib/l10n/app_pt_pt.arb

  • Adds European Portuguese translation for remoteViewModeActive key:
    "Modo de visualização remota - As alterações de configuração estão
    desativadas"
+1/-0     
app_it.arb
Italian Localization for Remote View Mode Banner                 

lib/l10n/app_it.arb

  • Adds Italian translation for remoteViewModeActive key: "Modalità
    visualizzazione remota - Le modifiche alle impostazioni sono
    disabilitate"
+1/-0     
app_fr.arb
French Localization for Remote View Mode Banner                   

lib/l10n/app_fr.arb

  • Adds French translation for remoteViewModeActive key: "Mode affichage
    à distance - Les modifications de paramètres sont désactivées"
+1/-0     
app_pt.arb
Brazilian Portuguese Localization for Remote View Mode Banner

lib/l10n/app_pt.arb

  • Adds Brazilian Portuguese translation for remoteViewModeActive key:
    "Modo de visualização remota - As alterações de configuração estão
    desativadas"
+1/-0     
app_nb.arb
Norwegian Bokmål Localization for Remote View Mode Banner

lib/l10n/app_nb.arb

  • Adds Norwegian Bokmål translation for remoteViewModeActive key:
    "Ekstern visningsmodus - Innstillingsendringer er deaktivert"
+1/-0     
app_es.arb
Spanish Localization for Remote View Mode Banner                 

lib/l10n/app_es.arb

  • Adds Spanish translation for remoteViewModeActive key: "Modo de
    visualización remota - Los cambios de configuración están
    deshabilitados"
+1/-0     
app_es_ar.arb
Argentine Spanish Localization for Remote View Mode Banner

lib/l10n/app_es_ar.arb

  • Adds Argentine Spanish translation for remoteViewModeActive key: "Modo
    de visualización remota - Los cambios de configuración están
    deshabilitados"
+1/-0     
app_nl.arb
Dutch Localization for Remote View Mode Banner                     

lib/l10n/app_nl.arb

  • Adds Dutch translation for remoteViewModeActive key: "Externe
    weergavemodus - Instellingswijzigingen zijn uitgeschakeld"
+1/-0     
app_de.arb
German Localization for Remote View Mode Banner                   

lib/l10n/app_de.arb

  • Adds German translation for remoteViewModeActive key:
    "Fernansichtsmodus - Einstellungsänderungen sind deaktiviert"
+1/-0     
app_id.arb
Indonesian Localization for Remote View Mode Banner           

lib/l10n/app_id.arb

  • Adds Indonesian translation for remoteViewModeActive key: "Mode
    Tampilan Jarak Jauh - Perubahan pengaturan dinonaktifkan"
+1/-0     
app_zh.arb
Simplified Chinese Localization for Remote View Mode Banner

lib/l10n/app_zh.arb

  • Adds Simplified Chinese translation for remoteViewModeActive key:
    "远程查看模式 - 无法修改设置"
+1/-0     
app_en.arb
English Localization for Remote View Mode Banner                 

lib/l10n/app_en.arb

  • Adds English translation for remoteViewModeActive key: "Remote View
    Mode - Setting changes are disabled"
+1/-0     

PeterJhongLinksys and others added 26 commits January 21, 2026 16:40
Add immutable state class to represent remote read-only mode status.
Includes toMap/fromMap/toJson/fromJson methods per constitution Article XI.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add Riverpod provider to centralize remote read-only mode detection.
Provider watches authProvider and BuildConfig to determine access mode.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add banner component to display remote read-only mode notification.
Banner appears when isRemoteReadOnly is true, hidden otherwise.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add RemoteReadOnlyBanner to root layout Stack.
Banner appears at top when in remote read-only mode.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Block SET operations when in remote read-only mode at the repository level.
This provides a final layer of defense to prevent configuration changes
when accessing the router remotely.

Changes:
- Add _isSetOperation() helper to detect SET operations by URL path
- Add _isRemoteReadOnly() helper to check remote access state
- Block SET operations in send() method when in remote mode
- Block transactions containing SET operations when in remote mode
- Throw UnexpectedError with descriptive message when blocked
- Add comprehensive test coverage for defensive checks

GET operations and non-SET operations remain unaffected in remote mode.
All operations are allowed in local mode.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…pproach

Switch from blacklist (checking 'set*' prefix) to allowlist (only allowing
'get*', 'is*', 'check*' operations) to close security vulnerability.

The previous implementation only blocked operations starting with "Set",
which allowed bypass through destructive operations like reboot, factoryReset,
and deleteDevice. This fix uses an allowlist of safe read-only operations
instead, blocking all operations that are NOT explicitly safe.

Changes:
- Rename _isSetOperation() to _isReadOnlyOperation()
- Implement allowlist with safePrefixes: get, is, check
- Invert defensive check logic (!_isReadOnlyOperation)
- Update error messages to reference "Write operations"
- Add comprehensive tests for blocking destructive operations
- Fix tests to use truly safe operations (getDeviceInfo, getWANSettings)

All 10 tests passing.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Create comprehensive usage guide showing developers how to:
- Check remote read-only status in UI components
- Disable different control types (buttons, switches, text fields)
- Follow best practices (use select(), disable vs hide)
- Write tests for remote mode behavior
- Understand the defensive layer protection

Includes code examples, testing patterns, and related file references.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Change RootContainer layout from Stack with Positioned to Column with
Expanded. This makes the banner occupy actual space instead of floating
over content, preventing UI elements from being obscured.

Before: Banner used Positioned(top: 0) - overlays content
After: Banner in Column with Expanded content - pushes content down

All tests passing.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Replace hardcoded Colors.orange with theme-aware colors to match
application design system:
- Background: colorScheme.secondaryContainer
- Text/Icon: colorScheme.onSecondaryContainer
- Text style: textTheme.bodyMedium

This ensures the banner integrates seamlessly with both light and dark
themes without appearing jarring or out of place.

Update tests to verify theme color usage.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Design comprehensive UI layer protection for remote read-only mode:

Architecture:
- Layer 1: UI Controls (RemoteAwareSwitch + UiKitBottomBarConfig)
- Layer 2: User Notification (existing banner)
- Layer 3: Service Defense (existing RouterRepository checks)

Key Components:
- RemoteAwareSwitch: Wrapper for immediate-effect switches
- UiKitBottomBarConfig enhancement: Auto-disable Save buttons

Two Operation Modes:
- Immediate Mode: Switches trigger JNAP operations directly
- Form Mode: Changes batched with Save button

Implementation Strategy:
- Phase 1: Core components (RemoteAwareSwitch + UiKitBottomBarConfig)
- Phase 2: Replace immediate mode switches (15-20 estimated)
- Phase 3: Verification & testing

Complete with testing strategy, edge cases, migration guide, and
success criteria.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Complete step-by-step implementation plan with 12 tasks:

Phase 1 - Core Components (Tasks 1-6):
- RemoteAwareSwitch component with TDD approach
- UiKitBottomBarConfig enhancement for auto-disable Save buttons

Phase 2 - Switch Replacement (Tasks 7-9):
- Catalog all AppSwitch usages and categorize by mode
- Systematic replacement of immediate-mode switches
- Batch commits for reviewability

Phase 3 - Verification (Tasks 10-12):
- Integration testing
- Full test suite validation
- Documentation updates

Each task includes:
- Exact file paths and line numbers
- Complete code snippets
- Test commands with expected output
- Commit messages

Estimated effort: 6-11 hours

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Replace string comparison with nodeType == 'Master' with semantic
property check using device.isMaster for better code clarity.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…test

Add wrapper component for AppSwitch that auto-disables in remote mode.
Initial test verifies switch is enabled in local mode.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Verify switch is disabled (onChanged = null) in remote mode.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…sabled

Ensure switch value displays correctly even when disabled in remote mode.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…nges

Ensure switch state updates reactively when loginType transitions between
local and remote modes.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…onfig

Add optional parameter to control whether Save button should be disabled
in remote mode. Defaults to true for automatic protection.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Modify _buildBottomBarConfig to check remoteAccessProvider and disable
positive button when isRemoteReadOnly is true. Respects checkRemoteReadOnly
flag for opt-out scenarios.

All form pages using UiKitBottomBarConfig now automatically protected.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Comprehensive review of all AppSwitch usages categorized by operation mode.
Identifies 10 switches requiring replacement with RemoteAwareSwitch:
- instant_admin_view.dart (1): Firmware update toggle
- wifi_card.dart (1): WiFi enable/disable
- vpn_status_tile.dart (1): VPN service toggle
- quick_panel.dart (6): Dashboard quick actions
- instant_privacy_view.dart (1): Instant Privacy toggle

13 switches auto-protected by UiKitBottomBarConfig in form pages.
4 switches are UI-only and require no action.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Replace immediate-mode switches in:
- instant_admin_view.dart: Auto firmware update toggle
- wifi_card.dart: WiFi network enable/disable toggle
- vpn_status_tile.dart: VPN service enable/disable toggle

These switches directly trigger JNAP operations and must be disabled
in remote mode.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Replace immediate-mode switches in:
- quick_panel.dart: 6 switches across 3 display modes
  * Compact mode: Instant Privacy and Night Mode toggles
  * Normal mode: Instant Privacy and Night Mode toggles
  * Expanded mode: Instant Privacy and Night Mode toggles
- instant_privacy_view.dart: Instant Privacy enable/disable toggle

These switches directly trigger JNAP operations and must be disabled
in remote mode.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…KitBottomBarConfig

Add comprehensive usage documentation for:
- RemoteAwareSwitch component for immediate-effect switches
- UiKitBottomBarConfig automatic Save button protection
- When to use each approach
- Opt-out scenarios

Updated Related Files section with new components and tests.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Complete verification report documenting:
- All 10 immediate-mode switches replaced with RemoteAwareSwitch
- 13 form pages auto-protected by UiKitBottomBarConfig
- All 2756 tests passing (no regressions)
- 32 remote-access specific tests passing
- Manual testing checklist for final verification
- Complete list of affected files and commits

Implementation ready for production deployment.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…ol support

Enable read-only diagnostic operations in remote mode while maintaining
security restrictions on configuration changes. This provides better user
experience for remote troubleshooting without compromising device security.

Changes:
- Add safe operations whitelist for LED blinking, speed test, ping, and traceroute
- Remove remote restrictions from SpeedTest widget and external speed test links
- Implement topology menu remote mode controls (disable reboot, pair, reset)
- Add 26-language translations for featureUnavailableInRemoteMode message
- Apply remote read-only checks to IPv4/IPv6 connection and DHCP settings
- Enhance RemoteReadOnlyBanner visual styling
- Add comprehensive test coverage for safe operations (14 test cases)

Read-only operations now allowed in remote mode:
- LED blinking (startBlinkingNodeLed, stopBlinkingNodeLed)
- Speed test (runHealthCheck, stopHealthCheck)
- Network diagnostics (startPing, stopPing, startTraceroute, stopTraceroute)

Co-Authored-By: Claude <noreply@anthropic.com>
…istance

# Conflicts:
#	lib/page/instant_admin/views/instant_admin_view.dart
- Wrap dialog content in SingleChildScrollView to support long JSON strings

- Move action buttons to AlertDialog actions property to ensure visibility
@qodo-code-review
Copy link

qodo-code-review bot commented Jan 28, 2026

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
Sensitive data exposure

Description: The export dialog renders the full jsonString configuration and provides a "Copy to
Clipboard" action, which can expose sensitive configuration data (e.g., API keys, tokens,
passwords, Wi‑Fi credentials) via on-screen display, clipboard history, or paste into
other apps, depending on what the exported configuration contains.
theme_studio_panel.dart [141-173]

Referred Code
builder: (context) {
  return AlertDialog(
    title: const Text('Export Configuration'),
    content: SingleChildScrollView(
      child: SelectableText(
        jsonString,
        style: TextStyle(
          fontFamily: 'monospace',
          fontSize: 12,
          color: Theme.of(context).colorScheme.onSurface,
        ),
      ),
    ),
    actions: [
      AppButton.text(
        label: 'Close',
        onTap: () => Navigator.of(context).pop(),
      ),
      const SizedBox(width: 8),
      AppButton.primary(
        label: 'Copy to Clipboard',


 ... (clipped 12 lines)
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

🔴
Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Allowlist mismatch: _isReadOnlyOperation allowlists starttraceroute/stoptraceroute, but the PR tests and
codebase actions appear to use startTracroute/stopTracroute (lowercased
starttracroute/stoptracroute), which would be incorrectly treated as a write operation and
blocked in remote mode.

Referred Code
/// Checks if the given JNAP action is a read-only operation.
///
/// Only operations that do NOT modify router configuration are considered safe.
/// Safe operations include Get*, Is*, Check*, LED blinking, speed test,
/// and network diagnostic operations (ping, traceroute).
/// All other operations are blocked in remote read-only mode.
bool _isReadOnlyOperation(JNAPAction action) {
  final actionValue = action.actionValue;
  // Extract the last segment of the URL path (after the last '/')
  final lastSegment = actionValue.split('/').last.toLowerCase();

  // Allowlist of safe read-only operation prefixes
  const safePrefixes = [
    'get', // Get operations (getDeviceInfo, getWANSettings, etc.)
    'is', // Status checks (isAdminPasswordDefault, etc.)
    'check', // Validation operations (checkAdminPassword, etc.)
  ];

  // Allowlist of specific safe operations that don't modify configuration
  const safeOperations = [
    'startblinkingnodeled', // LED blinking operations


 ... (clipped 12 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
Missing audit logging: The new remote read-only defensive blocks throw an error but do not record an audit event
(user/context/action/outcome), so it is unclear whether critical blocked write attempts
are captured in the system audit trail.

Referred Code
/// Checks if the given JNAP action is a read-only operation.
///
/// Only operations that do NOT modify router configuration are considered safe.
/// Safe operations include Get*, Is*, Check*, LED blinking, speed test,
/// and network diagnostic operations (ping, traceroute).
/// All other operations are blocked in remote read-only mode.
bool _isReadOnlyOperation(JNAPAction action) {
  final actionValue = action.actionValue;
  // Extract the last segment of the URL path (after the last '/')
  final lastSegment = actionValue.split('/').last.toLowerCase();

  // Allowlist of safe read-only operation prefixes
  const safePrefixes = [
    'get', // Get operations (getDeviceInfo, getWANSettings, etc.)
    'is', // Status checks (isAdminPasswordDefault, etc.)
    'check', // Validation operations (checkAdminPassword, etc.)
  ];

  // Allowlist of specific safe operations that don't modify configuration
  const safeOperations = [
    'startblinkingnodeled', // LED blinking operations


 ... (clipped 85 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status:
Logging not evidenced: The PR introduces new security-relevant decision points (remote read-only blocking) but
adds no structured logging, so it cannot be verified from the diff whether logs remain
structured and free of sensitive data.

Referred Code
Future<JNAPSuccess> send(
  JNAPAction action, {
  Map<String, dynamic> data = const {},
  Map<String, String> extraHeaders = const {},
  bool auth = false,
  CommandType? type,
  bool fetchRemote = false,
  CacheLevel? cacheLevel,
  int timeoutMs = 10000,
  int retries = 1,
  SideEffectPollConfig? pollConfig,
}) async {
  // Defensive check: Block write operations in remote read-only mode
  if (!_isReadOnlyOperation(action) && _isRemoteReadOnly()) {
    throw const UnexpectedError(
      message: 'Write operations are not allowed in remote read-only mode',
    );
  }

  cacheLevel ??= isMatchedJNAPNoCachePolicy(action)
      ? CacheLevel.noCache


 ... (clipped 41 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Heuristic classification: Remote-mode write blocking relies on parsing action.actionValue string segments and prefix
heuristics, which may misclassify actions if naming/paths change, so the completeness of
authorization-style enforcement cannot be confirmed from the diff alone.

Referred Code
/// Checks if the given JNAP action is a read-only operation.
///
/// Only operations that do NOT modify router configuration are considered safe.
/// Safe operations include Get*, Is*, Check*, LED blinking, speed test,
/// and network diagnostic operations (ping, traceroute).
/// All other operations are blocked in remote read-only mode.
bool _isReadOnlyOperation(JNAPAction action) {
  final actionValue = action.actionValue;
  // Extract the last segment of the URL path (after the last '/')
  final lastSegment = actionValue.split('/').last.toLowerCase();

  // Allowlist of safe read-only operation prefixes
  const safePrefixes = [
    'get', // Get operations (getDeviceInfo, getWANSettings, etc.)
    'is', // Status checks (isAdminPasswordDefault, etc.)
    'check', // Validation operations (checkAdminPassword, etc.)
  ];

  // Allowlist of specific safe operations that don't modify configuration
  const safeOperations = [
    'startblinkingnodeled', // LED blinking operations


 ... (clipped 22 lines)

Learn more about managing compliance generic rules or creating your own custom rules

  • Update
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review
Copy link

qodo-code-review bot commented Jan 28, 2026

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Include traceroute variants in safe operations

Add alternate spellings for traceroute actions to the safeOperations list to
prevent them from being incorrectly blocked in remote mode.

lib/core/jnap/router_repository.dart [93-103]

-// Allowlist of specific safe operations that don't modify configuration
 const safeOperations = [
-  'startblinkingnodeled', // LED blinking operations
+  'startblinkingnodeled',
   'stopblinkingnodeled',
-  'runhealthcheck', // Speed test operations (read-only, no config changes)
+  'runhealthcheck',
   'stophealthcheck',
-  'startping', // Network diagnostic operations (read-only)
+  'startping',
   'stopping',
   'starttraceroute',
   'stoptraceroute',
+  // also support the alternate spelling from JNAPAction.startTracroute
+  'starttracroute',
+  'stoptracroute',
 ];
  • Apply / Chat
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies that startTracroute and stopTracroute actions would be incorrectly blocked due to a spelling mismatch, and fixing it prevents a runtime bug.

High
Use secondaryContainer for banner background

Change the banner's background color from errorContainer to secondaryContainer
to align with the test expectations.

lib/page/components/views/remote_read_only_banner.dart [26-37]

 return Container(
   width: double.infinity,
   padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
   decoration: BoxDecoration(
-    color: colorScheme.errorContainer,
+    color: colorScheme.secondaryContainer,
     border: Border(
       bottom: BorderSide(
         color: colorScheme.error.withValues(alpha: 0.3),
         width: 2,
       ),
     ),
   ),
   child: Row(...

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 7

__

Why: The suggestion fixes a discrepancy between the banner's implementation, which uses errorContainer, and its test, which asserts the use of secondaryContainer, resolving a test failure.

Medium
High-level
Re-evaluate disabling the speed test

The speed test UI is disabled in remote mode, but the backend whitelists it as a
safe operation. This is inconsistent and should be aligned.

Examples:

lib/core/jnap/router_repository.dart [97-98]
      'runhealthcheck', // Speed test operations (read-only, no config changes)
      'stophealthcheck',
lib/page/dashboard/views/components/widgets/composite/port_and_speed.dart [364-366]
        opacity: isRemoteReadOnly ? 0.5 : 1,
        child: AbsorbPointer(
          absorbing: isRemoteReadOnly,

Solution Walkthrough:

Before:

// UI: Speed test is disabled in remote mode
// File: lib/page/dashboard/views/components/widgets/composite/port_and_speed.dart
final isRemoteReadOnly = ref.watch(remoteAccessProvider).isRemoteReadOnly;
return Opacity(
  opacity: isRemoteReadOnly ? 0.5 : 1,
  child: AbsorbPointer(
    absorbing: isRemoteReadOnly, // UI interaction is blocked
    child: SpeedTestWidget(),
  ),
);

// Backend: Speed test operations are allowed in remote mode
// File: lib/core/jnap/router_repository.dart
bool _isReadOnlyOperation(JNAPAction action) {
  const safeOperations = [
    'runhealthcheck', // Whitelisted
    'stophealthcheck', // Whitelisted
    ...
  ];
  // ... logic allows these operations
}

After:

// UI: Speed test is enabled in remote mode (aligned with backend)
// File: lib/page/dashboard/views/components/widgets/composite/port_and_speed.dart
// The logic that disables the speed test widget is removed.
return Opacity(
  opacity: 1.0, // Always fully visible
  child: AbsorbPointer(
    absorbing: false, // UI interaction is always allowed
    child: SpeedTestWidget(),
  ),
);


// Backend: Speed test operations are allowed in remote mode (no change)
// File: lib/core/jnap/router_repository.dart
bool _isReadOnlyOperation(JNAPAction action) {
  const safeOperations = [
    'runhealthcheck',
    'stophealthcheck',
    ...
  ];
  // ... logic allows these operations
}
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies a significant logical inconsistency between the UI and backend implementation for the speed test feature, which impacts user-facing functionality.

Medium
General
Use a more appropriate banner icon
Suggestion Impact:The banner icon was updated from Icons.shield_outlined to Icons.info_outline as suggested.

code diff:

@@ -38,7 +38,7 @@
       child: Row(
         children: [
           Icon(
-            Icons.shield_outlined,
+            Icons.info_outline,
             color: colorScheme.onErrorContainer,

Change the banner icon from Icons.shield_outlined to Icons.info_outline to match
the test expectation and better convey a warning status.

lib/page/components/views/remote_read_only_banner.dart [26-58]

 return Container(
   width: double.infinity,
   padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
   decoration: BoxDecoration(
     color: colorScheme.errorContainer,
     border: Border(
       bottom: BorderSide(
-        color: colorScheme.error.withValues(alpha: 0.3),
+        color: colorScheme.error.withOpacity(0.3),
         width: 2,
       ),
     ),
   ),
   child: Row(
     children: [
       Icon(
-        Icons.shield_outlined,
+        Icons.info_outline,
         color: colorScheme.onErrorContainer,
         size: 24,
       ),
       const SizedBox(width: 12),
       Expanded(
         child: Text(
           loc(context).remoteViewModeActive,
           style: textTheme.bodyLarge?.copyWith(
             color: colorScheme.onErrorContainer,
             fontWeight: FontWeight.w600,
           ),
         ),
       ),
     ],
   ),
 );

[Suggestion processed]

Suggestion importance[1-10]: 7

__

Why: The suggestion aligns the banner's icon with its corresponding test, which expects Icons.info_outline instead of Icons.shield_outlined, fixing a test failure introduced in the PR.

Medium
  • Update

- Change icon from shield_outlined to info_outline for better visual semantic
…mote_assistance"

This reverts commit 63a1f6b, reversing
changes made to cd60b3b.
- Add missing localization setup for AppLocalizations

- Update color expectation to match implementation
This reverts commit b133403. This restores the original merge of dev-2.0.0, resulting in the re-application of changes to specifications, tests, and core logic that were previously reverted.
- Remove fetchRemote: true from getDeviceInfo call in SessionService to ensure correct session verification behavior.
Copy link
Collaborator

@AustinChangLinksys AustinChangLinksys left a comment

Choose a reason for hiding this comment

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

looks good to me

@AustinChangLinksys AustinChangLinksys merged commit dfaa782 into dev-2.0.0 Feb 3, 2026
2 checks passed
@AustinChangLinksys AustinChangLinksys deleted the peter/remote_assistance branch February 3, 2026 08:13
@PeterJhongLinksys PeterJhongLinksys linked an issue Feb 4, 2026 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remote assistance revisit

2 participants