Commit Graph

2 Commits

Author SHA1 Message Date
evgeniyChepelev 0327624b30 Multi-profiles (#80)
* fix layout on ipad

* Create multi profiles

* multi-profile server config, connection cache, and auth fixes

 Split ProfilesView into ProfilesListView, AddProfileSheet, ProfileBadge, AddProfileViewModel
- Add server URL + setup key fields to Add Profile screen
- Store per-profile connection data (ip/fqdn/managementURL) as typed model in ProfileConnectionCache
- Show cached connection info immediately on profile switch; empty if no prior data
- Fix profile deletion persistence via tombstone in profiles.json
- Fix logout to remove both netbird.cfg and state.json (cfg holds auth tokens)
- Preserve managementURL in UI after logout via cache fallback
- Guard polling from overwriting new profile's data during disconnect/reconnect cycle

* fix(multi-profile): reinitialize VPN adapter on profile switch and show current server URL

* Update project.pbxproj

* fix(multi-profile): prevent default server overwrite on logout/re-login

* Update PacketTunnelProvider.swift

* fix(multi-profile): address code review findings

- Normalize only scheme and host to lowercase when saving management
  server URL; previously the full URL was lowercased which could corrupt
  case-sensitive paths on self-hosted servers
- Move switchConnectionInfo(to:) inside the do-block so the connection
  UI is only updated after a successful profile switch
- Add ProfileConnectionCache.remove(for:) and clearConnectionData(for:)
  to prevent stale ip/fqdn/managementURL from persisting after a profile
  is deleted or logged out; call them from removeProfile and logoutProfile
- Use ASWebAuthenticationSession.Callback.customScheme on iOS 17.4+,
  falling back to the deprecated callbackURLScheme initializer on older
  versions; add a comment explaining why "http" is used and that a
  proper fix requires custom-scheme support in the SDK
- Guard presentationAnchor against a missing key window with
  assertionFailure in debug builds instead of silently returning an
  empty UIWindow
2026-04-22 10:06:51 +02:00
shuuri-labs 4c2791ca60 Add tvOS (Apple TV) support for NetBird VPN client (#36)
* Add tvOS (Apple TV) support for NetBird VPN client

This commit introduces full tvOS support for the NetBird iOS client,
enabling VPN connectivity on Apple TV devices.

- Added NetBird TV app target with tvOS 16.0+ deployment
- Created tvOS-specific UI using SwiftUI optimized for "10-foot experience"
- Tab-based navigation: Connection, Peers, Networks, Settings
- Large touch targets and text for Siri Remote navigation

- TVMainView: Main tab navigation and connection status
- TVConnectionView: Large connect/disconnect button with status display
- TVPeersView: List of connected peers with connection details
- TVNetworksView: Network routes selection and management
- TVSettingsView: App settings and logout functionality
- TVAuthView: QR code + device code authentication flow

- Implemented OAuth device authorization flow for tvOS
- Displays QR code that user scans with phone to authenticate
- Shows user code as fallback for manual entry
- Polls for authentication completion and auto-dismisses on success

tvOS has stricter sandbox restrictions than iOS:

1. **UserDefaults-based Config Storage**
   - tvOS blocks file writes to App Group containers
   - Config stored in shared UserDefaults instead of files
   - Added Preferences methods: saveConfigToUserDefaults(),
     loadConfigFromUserDefaults(), hasConfigInUserDefaults()

2. **Preloaded Config in Go SDK**
   - SDK modified to accept config via setConfigFromJSON()
   - Avoids file I/O that would fail in tvOS sandbox
   - Config passed from UserDefaults to SDK at runtime

3. **Raw Syscall Tunnel FD Discovery**
   - tvOS SDK doesn't expose ctl_info, sockaddr_ctl, CTLIOCGINFO
   - Implemented findTunnelFileDescriptorTvOS() using raw memory ops
   - Manually defines kernel structure layouts at byte level
   - Uses getpeername() and ioctl() which ARE available on tvOS

- Added NetBirdTVNetworkExtension target
- Separate PacketTunnelProvider.swift with tvOS-specific handling
- Extensive logging for debugging via Console.app
- Handles "LoginTV" message for device auth flow
- Loads config from UserDefaults into SDK memory

- isLoginRequired() now verifies session with management server
- Previously only checked if config existed (caused post-restart failures)
- Shows QR code re-auth flow when OAuth session expires

- Added Platform.swift for iOS/tvOS conditional compilation
- Shared code uses #if os(tvOS) / #if os(iOS) where needed
- Common ViewModels work across both platforms

* cleanup

* fixed slow startup + added images

* fixed active networks not refreshing

* fix occasional failure of first connection

* hostname properly set + removed debug logging

* - Fix "invalid Prefix" display on Networks tab by showing route name
- Update ServerViewModel to use new SDK callback-based API
- Fix focus navigation on Networks and Settings tabs
- Add white text on focus for better readability across all cards
- Increase filter bar spacing to prevent highlight overlap
- Add TVSettingsInfoRow for non-interactive display items

* Fixed focus escape bug on 'change server' dialog

* fixed switching of management servers

* fixes for change server settings menu

* - Extract TVColors and TVLayout to shared TVColors.swift
- Remove duplicate TVColors structs from 5 TV view files
- Add ClearConfig IPC message to clear extension-local config on logout
- Switch MainView from viewModel.isIpad to DeviceType.isPad
- Remove unused isTV/isIpad properties from MainViewModel
- Add TVColors.swift to Xcode project

* apply recommended xcode settings

* display correct app name in tvOS UI

* added tv-specific assets, updated readme

* updated readme

* - Add checkLoginError IPC to detect extension login failures
- Remove dead shared UserDefaults fallback code in NetBirdAdapter
- Document tvOS config storage architecture in Preferences.swift
- Fix onChange deprecation warnings in TVSettingsView
- Add "no peer auth method" detection in ServerViewModel

* Fix CodeRabbit review issues: bundle IDs, force-unwraps, and error handling

- Fix mismatched bundle IDs between Debug/Release configs for tvOS targets
- Make Preferences.configFile() and stateFile() return optionals instead of
  force-unwrapping, with proper error logging when app group unavailable
- Make NetBirdAdapter.init failable to handle SDK client creation failures
- Fail fast in NetBirdAdapter.start() when tunnel file descriptor is invalid
  instead of silently passing fd=0 (stdin) to the SDK
- Ensure all handleAppMessage switch cases call completionHandler to prevent
  IPC callers from hanging indefinitely

* - Delete unused updateManagementURL() and setSetupKey() functions
  (functionality migrated to ServerViewModel)
- Remove orphaned managementURL property
- Simplify supportsKeyboard to just return true (both branches were identical)
- Updated README instructions on buiilding tvOS SDK (needs NetBird gomobile fork)

* Fix tvOS build issues from CodeRabbit review

- Use empty configPath on tvOS in loginAsync() since config uses UserDefaults
- Add JSON escaping in updateDeviceNameInConfig() for special characters
- Standardize TVOS_DEPLOYMENT_TARGET to 17.0 across all configurations
- Add missing CODE_SIGN_ENTITLEMENTS to NetBird TV Release config

* added empty box asset to tvOS app

* - Preferences.swift: Use #if os(iOS) / #else for platform-specific
  newPreferences() - iOS returns non-optional with preconditionFailure
  on misconfiguration, tvOS returns nil by design (uses IPC not SDK)

- MainViewModel: Wrap preferences property and SDK methods (rosenpass,
  presharedKey) in platform conditionals. Add tvOS stubs for methods
  called from shared UI. Wrap IPC flag methods (checkLoginRequiredFlag,
  checkNetworkUnavailableFlag) since App Group UserDefaults are
  isolated sandboxes on tvOS.

- PacketTunnelProvider: Fix optional unwrapping for clientState logging

- project.pbxproj: Add Platform.swift to iOS target (was tvOS-only)

* Add ConfigurationProvider protocol to abstract platform config storage

- Create ConfigurationProvider protocol with iOS/tvOS implementations
- iOS uses NetBirdSDKPreferences (file-based), tvOS uses UserDefaults
- Refactor MainViewModel to use ConfigurationProvider, removing platform
  conditionals and empty tvOS stubs
- tvOS now stores rosenpass/presharedKey settings locally (ready for
  future IPC integration)

* implemented rosenpass toggle

* implemented preshared key setting

* Update GitHub Actions to use macOS 15 with Xcode 16

Project uses Xcode 16 project format (objectVersion 70) which isn't
compatible with Xcode 15.x on macos-14 runners.

* Add tvOS app icons, Top Shelf images, and fix archive validation errors

- Add complete tvOS icon assets (App Icon, App Store Icon, Top Shelf)
- Add arm64 to UIRequiredDeviceCapabilities for TV Network Extension
- Add TVTopShelfImage configuration to tvOS Info.plist
- Fix iOS build cycle by reordering Embed Frameworks before Crashlytics script

* Fix tvOS SDK path and add config update logging

- Use SDKROOT for libresolv.tbd instead of hardcoded SDK version
- Add AppLogger warnings when config JSON updates fail

* re-added test targets to project.pbxproj (lost in merge)

* Replace regex-based JSON manipulation with JSONSerialization for
reading and writing config fields

* Address PR review feedback for tvOS support

- Add detailed comment explaining tvOS UserDefaults sync limitation
- Use AppLogger instead of print in Preferences.swift
- Remove unnecessary #if os() checks in tvOS PacketTunnelProvider
- Remove duplicate tvOS entitlement/plist files from NetBirdTV/
- Fix CI build destinations to use simulator

* Removed dead variables from TVPeersListContent, Updated tvOS config JSON parsing method

* update build platform (iphone 16 -> iphone 15) in an attempt to resolve github actions error

* update build platform in an attempt to resolve github actions error

* update xcode build runner an attempt to resolve github actions error

* update build.yml to specify downloading of ios 18.2 image to fix build error

* update build.yml to remove specifying of ios 18.2 image download

* downgrade macos build image to 14 to resolve ios build error on github

* downgrade macos build image to 14 to resolve ios build error on github

* upgrade build runner xcode version to 26.2 to resolve ios build error on github

* upgrade build runner xcode version to 26.2 to resolve ios build error on github

* upgrade build runner xcode version to 26.2 to resolve ios build error on github

* upgrade build runner xcode version to 26.1.1 to resolve ios build error on github

* upgrade build script sdk output path to resolve ios build error on github

* added create dummy GoogleService-Info.plist build step to github workflows

* Fix TVAuthView error UI not displaying by setting errorMessage state

* - replace pipe-delimited string parsing with typed LoginDiagnostics
struct

- removed unused initializeConfigViaExtension method and converted
some print statements to logger.debug for consistency

* more pipe -> struct refactoring

* update readme and buildscript to use gomobile-netbird for building sdk, sdk version bump

* fix initial connection bug that required user to press 'connect' again after completing sso flow

* improve app loading speed + add splash screen logo

* Fix race condition in tvOS VPN connection and revert Firebase to main thread

- Move startVPNConnection() inside sendConfigToExtension completion handler to ensure config transfer completes before VPN starts
- Revert Firebase initialization to main thread as required by Firebase documentation
- Keep ViewModelLoader with loading screen to improve perceived startup time
- Keep lazy NetworkExtensionAdapter.configureManager() call removed from init

* fix test github workflow

* fix TVColors.swift UUID in project.pbxproj

* fix gomobile-netbird run in github workflow by adding 'gomobile-netbird init' step

* Add gomobile-netbird init step to GitHub Actions workflow with proper PATH configuration

* revert build script changes

* bump network extension ver to 7 - apple states this should match the main app's ver #

* remove unused wireguardkitgo paths

* Fix version mismatch between iOS app and network extension

* Add diagnostic logging to test workflow to capture crash details

Capture full xcodebuild output and system crash logs when tests fail.
This will help debug the test crash that occurs during app bootstrapping
in CI but not locally.

- Tee test output to file before xcpretty filtering
- Search for and print crash reports from DiagnosticReports
- Upload test logs and crash reports as artifacts on failure

* use gomobile-netbird in build script, workflows

* update build workflow to use gomobile-netbird

* force pulling of latest gomobile-netbird

* install gobind manually rather than relying on gomobile init

* add gomobile-tvos-for support download module step to workflows

* checkout gomobile-tv-fork module instead of go mod, which doesn't play nicely with github actions

* Add gomobile-tvos-fork to netbird's go.mod so gobind can find bind package

* revert debugging for test workflow

* fix rosenpass toggle bug for ios - view does not read value from saved config so always appears as disabled

* temporarily disable test workflow
2026-01-16 20:58:34 +01:00