feat: WiFi hotspot port forwarding#8
Open
steffen-heil-secforge wants to merge 11 commits into
Open
Conversation
Pure-Kotlin utility object providing WiFi hotspot interface detection, private IPv4 validation, bind address resolution and display name helpers. All 23 unit tests pass (TDD, no Android framework dependencies). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add 6 unit tests for the pure-logic NetworkInterface overload of getHotspotInterfaceIP, covering: hotspot interface with private IPv4, empty list, cellular interface rejection, loopback rejection, IPv6 rejection, and first-match-wins with multiple interfaces. Uses the package-private JDK constructor (via reflection + --add-opens java.base/java.net=ALL-UNNAMED) to construct real NetworkInterface stubs without requiring mockito-inline or production-code changes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…x matching - Move getAccessPointIP() call inside synchronized block in hasAccessPointStateChanged to eliminate the race where two threads could both detect the same state change - Remove now-redundant @volatile annotation from lastKnownApIP - Fix isHotspotInterfaceName to treat "wlan1" as an exact match or non-numeric suffix only, preventing false positives on wlan10/wlan11 (multi-radio STA interfaces) - Add tests: wlan10/wlan11 rejection, wlan1 acceptance, hasAccessPointStateChanged change detection and no-change stability (using reflection + Mockito mock Context) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…in SSH Add resolveLocalBindAddress() helper that delegates to NetworkUtils to resolve the portForward.sourceAddr field (including the "wifi_hotspot" sentinel) into a concrete InetAddress. Replace hardcoded InetAddress.getLocalHost() with this resolver in both PORTFORWARD_LOCAL and PORTFORWARD_DYNAMIC5 branches of enablePortForward(). Returns false (with a Timber warning) when the hotspot bind is requested but the AP is currently unavailable. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add AccessPointReceiver + 10-second Timer fields to TerminalManager - Add updateAccessPointMonitoring() to start/stop polling when AP-bound forwards are present in active bridges - Add checkAccessPointStateChange() called by timer and receiver - Add retryFailedAccessPointForwards() to re-enable forwards on hotspot up - Add hasActiveAccessPointForwards() and updateAccessPointNotification() stub - Wire monitoring into openConnection() and onDisconnected() - Replace TODO comments in SSH.kt with real manager?.updateAccessPointNotification() calls for LOCAL and DYNAMIC5 forwards (enable and disable paths) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…urces - ConnectionNotifier: add 3-arg showRunningNotification(service, apIP, hasApForwards) that builds a BigTextStyle multiline notification when AP forwards are active; existing 1-arg overload now delegates to the new one with (null, false) - TerminalManager: updateAccessPointNotification() now passes apIP and hasActiveAccessPointForwards() to the new 3-arg overload - strings.xml: add notification_access_point_text, notification_ap_disabled_text, bind_localhost, bind_all_interfaces, bind_hotspot, security_warning_network_exposure, prompt_bind_address Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add BindAddressOption enum and radio-button UI to PortForwardEditorDialog so users can choose localhost, all-interfaces, or WiFi hotspot as the bind address when adding/editing LOCAL or DYNAMIC port forwards. Shows a security warning when a network-exposed option is selected. The chosen value is passed through the existing onSave callback as sourceAddr. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
A LOCAL/DYNAMIC port forward bound to the WiFi hotspot (sourceAddr == "wifi_hotspot") that is not enabled and whose hotspot is currently down is now rendered with strikethrough text in the port forward list, distinguishing it from a simply-disabled forward. The ViewModel resolves the current hotspot IP via NetworkUtils and exposes it in PortForwardListUiState.hotspotIp; the Screen uses that value to compute isDysfunctional and applies TextDecoration.LineThrough to the nickname Text. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Added missing Android permission required for accessing WiFi state in hotspot detection logic. Updated test to provide applicationContext parameter to PortForwardListViewModel constructor. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This was referenced Jun 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PortForward.sourceAddr(sentinel valuewifi_hotspot)NetworkUtilsobject detects active AP interfaces (ap0,wlan1,swlan*, etc.) and resolves the bind IPAccessPointReceiverBroadcastReceiver catchesWIFI_AP_STATE_CHANGEDfor instant response; 10 s polling timer inTerminalManagercovers cases where no broadcast firesACCESS_WIFI_STATEpermission added to manifestTest plan
./gradlew testOssDebugUnitTest— 34NetworkUtilsTestcases cover AP detection, bind address resolution, interface name matching🤖 Generated with Claude Code