diff --git a/README.md b/README.md index d8d21927..e8c54e11 100644 --- a/README.md +++ b/README.md @@ -29,8 +29,11 @@ ## Features - On-device debugging/Just-In-Time (JIT) compilation for supported apps via [`idevice`](https://github.com/jkcoxson/idevice). -- Seamless integration with our custom built loopback vpn. -- Native UI for managing debugging/JIT-enabling. +- Seamless integration with **StikVPN**, our custom loopback VPN. +- Built-in StikVPN management to enable or disable the connection. +- Ability to edit the StikVPN device and fake IP addresses. +- Option to disable StikVPN auto start at launch. +- Native UI for managing debugging/JIT-enabling. - No data collection—ensuring full privacy. ## License diff --git a/StikDebug.xcodeproj/project.pbxproj b/StikDebug.xcodeproj/project.pbxproj index 4a85ee65..85cbd717 100644 --- a/StikDebug.xcodeproj/project.pbxproj +++ b/StikDebug.xcodeproj/project.pbxproj @@ -7,45 +7,7 @@ objects = { /* Begin PBXBuildFile section */ - DC139F6E2DE97EA400F63846 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC139F6D2DE97EA400F63846 /* WidgetKit.framework */; }; - DC139F702DE97EA400F63846 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC139F6F2DE97EA400F63846 /* SwiftUI.framework */; }; - DC139F812DE97EA600F63846 /* DebugWidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = DC139F6C2DE97EA400F63846 /* DebugWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; - DCA690122DAF660E007C91A8 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCA690112DAF660E007C91A8 /* NetworkExtension.framework */; }; DCA6901A2DAF660E007C91A8 /* TunnelProv.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = DCA690102DAF660E007C91A8 /* TunnelProv.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - DC139F7F2DE97EA600F63846 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = DC6F1D2F2D94EADD0071B2B6 /* Project object */; - proxyType = 1; - remoteGlobalIDString = DC139F6B2DE97EA400F63846; - remoteInfo = DebugWidgetExtension; - }; - DC6F1D492D94EADF0071B2B6 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = DC6F1D2F2D94EADD0071B2B6 /* Project object */; - proxyType = 1; - remoteGlobalIDString = DC6F1D362D94EADD0071B2B6; - remoteInfo = StikJIT; - }; - DC6F1D532D94EADF0071B2B6 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = DC6F1D2F2D94EADD0071B2B6 /* Project object */; - proxyType = 1; - remoteGlobalIDString = DC6F1D362D94EADD0071B2B6; - remoteInfo = StikJIT; - }; - DCA690182DAF660E007C91A8 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = DC6F1D2F2D94EADD0071B2B6 /* Project object */; - proxyType = 1; - remoteGlobalIDString = DCA6900F2DAF660E007C91A8; - remoteInfo = TunnelProv; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ DCA6901F2DAF660E007C91A8 /* Embed Foundation Extensions */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -58,58 +20,76 @@ name = "Embed Foundation Extensions"; runOnlyForDeploymentPostprocessing = 0; }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - DC139F6C2DE97EA400F63846 /* DebugWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = DebugWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; - DC139F6D2DE97EA400F63846 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; }; - DC139F6F2DE97EA400F63846 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; }; - DC139F862DE97F2000F63846 /* DebugWidgetExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugWidgetExtension.entitlements; sourceTree = ""; }; DC6F1D372D94EADD0071B2B6 /* StikDebug.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = StikDebug.app; sourceTree = BUILT_PRODUCTS_DIR; }; - DC6F1D482D94EADF0071B2B6 /* StikDebugTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = StikDebugTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - DC6F1D522D94EADF0071B2B6 /* StikDebugUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = StikDebugUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - DCA690102DAF660E007C91A8 /* TunnelProv.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = TunnelProv.appex; sourceTree = BUILT_PRODUCTS_DIR; }; - DCA690112DAF660E007C91A8 /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; }; -/* End PBXFileReference section */ - -/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ - 1775D3612D9644FD00DFA8E0 /* Exceptions for "StikJIT" folder in "StikDebug" target */ = { - isa = PBXFileSystemSynchronizedBuildFileExceptionSet; - membershipExceptions = ( - idevice/libem_proxy.a, - Info.plist, +DCA6901F2DAF660E007C91A8 /* Embed Foundation Extensions */ = { +isa = PBXCopyFilesBuildPhase; +buildActionMask = 2147483647; +dstPath = ""; +dstSubfolderSpec = 13; +files = ( +DC139F812DE97EA600F63846 /* DebugWidgetExtension.appex in Embed Foundation Extensions */, +DCA6901A2DAF660E007C91A8 /* TunnelProv.appex in Embed Foundation Extensions */, +); +name = "Embed Foundation Extensions"; +runOnlyForDeploymentPostprocessing = 0; +}; +B7EB91DC1EA781BE7A28356C /* Embed Foundation Extensions */ = { +isa = PBXCopyFilesBuildPhase; +buildActionMask = 2147483647; +dstPath = ""; +dstSubfolderSpec = 13; +files = ( +DC139F812DE97EA600F63846 /* DebugWidgetExtension.appex in Embed Foundation Extensions */, +DCA6901A2DAF660E007C91A8 /* TunnelProv.appex in Embed Foundation Extensions */, +); +name = "Embed Foundation Extensions"; +runOnlyForDeploymentPostprocessing = 0; +}; +DC6F1D372D94EADD0071B2B6 /* StikDebug.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = StikDebug.app; sourceTree = BUILT_PRODUCTS_DIR; }; +D1A90F1A02BB0F2DB34D7363 /* StikVPN.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = StikVPN.app; sourceTree = BUILT_PRODUCTS_DIR; }; +DC6F1D482D94EADF0071B2B6 /* StikDebugTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = StikDebugTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; ); - target = DC6F1D362D94EADD0071B2B6 /* StikDebug */; + path = StikJIT; + sourceTree = ""; }; - DC139F852DE97EA600F63846 /* Exceptions for "DebugWidget" folder in "DebugWidgetExtension" target */ = { - isa = PBXFileSystemSynchronizedBuildFileExceptionSet; - membershipExceptions = ( - Info.plist, + DC6F1D4F2D94EADF0071B2B6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( ); - target = DC139F6B2DE97EA400F63846 /* DebugWidgetExtension */; + runOnlyForDeploymentPostprocessing = 0; }; - DCA6901E2DAF660E007C91A8 /* Exceptions for "TunnelProv" folder in "TunnelProv" target */ = { - isa = PBXFileSystemSynchronizedBuildFileExceptionSet; - membershipExceptions = ( - Info.plist, + DCA6900D2DAF660E007C91A8 /* Frameworks */ = { + children = ( + DC6F1D372D94EADD0071B2B6 /* StikDebug.app */, + DC6F1D482D94EADF0071B2B6 /* StikDebugTests.xctest */, + DC6F1D362D94EADD0071B2B6 /* StikDebug */ = { + isa = PBXNativeTarget; + buildConfigurationList = DC6F1D5C2D94EADF0071B2B6 /* Build configuration list for PBXNativeTarget "StikDebug" */; + buildPhases = ( + DC6F1D332D94EADD0071B2B6 /* Sources */, + DC6F1D342D94EADD0071B2B6 /* Frameworks */, + DC6F1D352D94EADD0071B2B6 /* Resources */, + DCA6901F2DAF660E007C91A8 /* Embed Foundation Extensions */, ); - target = DCA6900F2DAF660E007C91A8 /* TunnelProv */; - }; -/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ - -/* Begin PBXFileSystemSynchronizedRootGroup section */ - DC139F712DE97EA400F63846 /* DebugWidget */ = { - isa = PBXFileSystemSynchronizedRootGroup; - exceptions = ( - DC139F852DE97EA600F63846 /* Exceptions for "DebugWidget" folder in "DebugWidgetExtension" target */, + buildRules = ( ); - path = DebugWidget; - sourceTree = ""; + dependencies = ( + DCA690192DAF660E007C91A8 /* PBXTargetDependency */, + DC139F802DE97EA600F63846 /* PBXTargetDependency */, + ); + fileSystemSynchronizedGroups = ( + DC6F1D392D94EADD0071B2B6 /* StikJIT */, + ); + name = StikDebug; + packageProductDependencies = ( + ); + productName = StikJIT; + productReference = DC6F1D372D94EADD0071B2B6 /* StikDebug.app */; + productType = "com.apple.product-type.application"; }; - DC6F1D392D94EADD0071B2B6 /* StikJIT */ = { - isa = PBXFileSystemSynchronizedRootGroup; - exceptions = ( - 1775D3612D9644FD00DFA8E0 /* Exceptions for "StikJIT" folder in "StikDebug" target */, + DC6F1D472D94EADF0071B2B6 /* StikDebugTests */ = { + A3B558DC13A56A19394DEFF7 /* Exceptions for "StikJIT" folder in "StikVPN" target */, ); path = StikJIT; sourceTree = ""; @@ -173,7 +153,21 @@ ); runOnlyForDeploymentPostprocessing = 0; }; -/* End PBXFrameworksBuildPhase section */ +DCA6900D2DAF660E007C91A8 /* Frameworks */ = { +isa = PBXFrameworksBuildPhase; +buildActionMask = 2147483647; +files = ( +DCA690122DAF660E007C91A8 /* NetworkExtension.framework in Frameworks */, +); +runOnlyForDeploymentPostprocessing = 0; +}; +F6923E8EEA863539CA3E4189 /* Frameworks */ = { +isa = PBXFrameworksBuildPhase; +buildActionMask = 2147483647; +files = ( +); +runOnlyForDeploymentPostprocessing = 0; +}; /* Begin PBXGroup section */ DC6F1D2E2D94EADD0071B2B6 = { @@ -192,8 +186,10 @@ }; DC6F1D382D94EADD0071B2B6 /* Products */ = { isa = PBXGroup; - children = ( - DC6F1D372D94EADD0071B2B6 /* StikDebug.app */, +children = ( +DC6F1D372D94EADD0071B2B6 /* StikDebug.app */, +D1A90F1A02BB0F2DB34D7363 /* StikVPN.app */, +DC6F1D482D94EADF0071B2B6 /* StikDebugTests.xctest */, DC6F1D482D94EADF0071B2B6 /* StikDebugTests.xctest */, DC6F1D522D94EADF0071B2B6 /* StikDebugUITests.xctest */, DCA690102DAF660E007C91A8 /* TunnelProv.appex */, @@ -308,27 +304,92 @@ productReference = DC6F1D522D94EADF0071B2B6 /* StikDebugUITests.xctest */; productType = "com.apple.product-type.bundle.ui-testing"; }; - DCA6900F2DAF660E007C91A8 /* TunnelProv */ = { - isa = PBXNativeTarget; - buildConfigurationList = DCA6901B2DAF660E007C91A8 /* Build configuration list for PBXNativeTarget "TunnelProv" */; - buildPhases = ( - DCA6900C2DAF660E007C91A8 /* Sources */, - DCA6900D2DAF660E007C91A8 /* Frameworks */, - DCA6900E2DAF660E007C91A8 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - fileSystemSynchronizedGroups = ( - DCA690132DAF660E007C91A8 /* TunnelProv */, +DCA6900F2DAF660E007C91A8 /* TunnelProv */ = { +isa = PBXNativeTarget; +buildConfigurationList = DCA6901B2DAF660E007C91A8 /* Build configuration list for PBXNativeTarget "TunnelProv" */; +buildPhases = ( +DCA6900C2DAF660E007C91A8 /* Sources */, +DCA6900D2DAF660E007C91A8 /* Frameworks */, +DCA6900E2DAF660E007C91A8 /* Resources */, +); +buildRules = ( +); +dependencies = ( +); +fileSystemSynchronizedGroups = ( +DCA690132DAF660E007C91A8 /* TunnelProv */, +); +name = TunnelProv; +packageProductDependencies = ( +); +productName = TunnelProv; +productReference = DCA690102DAF660E007C91A8 /* TunnelProv.appex */; +productType = "com.apple.product-type.app-extension"; +}; +DFF04EDE6402F55F2E04050D /* StikVPN */ = { +isa = PBXNativeTarget; +buildConfigurationList = D4AAA327FD7829CB8E395D8B /* Build configuration list for PBXNativeTarget "StikVPN" */; +buildPhases = ( +B0723274D8DBA733E7CFCBEB /* Sources */, +F6923E8EEA863539CA3E4189 /* Frameworks */, +4009A47AB5E9EEF641E2B9C2 /* Resources */, +B7EB91DC1EA781BE7A28356C /* Embed Foundation Extensions */, +); +buildRules = ( +); +dependencies = ( +DCA690192DAF660E007C91A8 /* PBXTargetDependency */, +DC139F802DE97EA600F63846 /* PBXTargetDependency */, +); +fileSystemSynchronizedGroups = ( +DC6F1D392D94EADD0071B2B6 /* StikJIT */, +); +name = StikVPN; +packageProductDependencies = ( +); +productName = StikVPN; +productReference = D1A90F1A02BB0F2DB34D7363 /* StikVPN.app */; +productType = "com.apple.product-type.application"; +}; +targets = ( +DC6F1D362D94EADD0071B2B6 /* StikDebug */, +DC6F1D472D94EADF0071B2B6 /* StikDebugTests */, +DC6F1D512D94EADF0071B2B6 /* StikDebugUITests */, +DCA6900F2DAF660E007C91A8 /* TunnelProv */, +DFF04EDE6402F55F2E04050D /* StikVPN */, +DC139F6B2DE97EA400F63846 /* DebugWidgetExtension */, +); +DCA6900E2DAF660E007C91A8 /* Resources */ = { +isa = PBXResourcesBuildPhase; +buildActionMask = 2147483647; +files = ( +); +runOnlyForDeploymentPostprocessing = 0; +}; +4009A47AB5E9EEF641E2B9C2 /* Resources */ = { +isa = PBXResourcesBuildPhase; +buildActionMask = 2147483647; +files = ( +); +runOnlyForDeploymentPostprocessing = 0; +}; ); - name = TunnelProv; - packageProductDependencies = ( - ); - productName = TunnelProv; - productReference = DCA690102DAF660E007C91A8 /* TunnelProv.appex */; - productType = "com.apple.product-type.app-extension"; +DCA6900C2DAF660E007C91A8 /* Sources */ = { +isa = PBXSourcesBuildPhase; +buildActionMask = 2147483647; +files = ( +); +runOnlyForDeploymentPostprocessing = 0; +}; +B0723274D8DBA733E7CFCBEB /* Sources */ = { +isa = PBXSourcesBuildPhase; +buildActionMask = 2147483647; +files = ( +); +runOnlyForDeploymentPostprocessing = 0; +}; + productReference = D1A90F1A02BB0F2DB34D7363 /* StikVPN.app */; + productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ @@ -384,22 +445,15 @@ /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - DC139F6A2DE97EA400F63846 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - DC6F1D352D94EADD0071B2B6 /* Resources */ = { + DCA6900E2DAF660E007C91A8 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; - DC6F1D462D94EADF0071B2B6 /* Resources */ = { - isa = PBXResourcesBuildPhase; + DCA6900C2DAF660E007C91A8 /* Sources */ = { + isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( ); @@ -422,6 +476,13 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + B0723274D8DBA733E7CFCBEB /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; DC139F682DE97EA400F63846 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -873,58 +934,132 @@ }; name = Debug; }; - DCA6901D2DAF660E007C91A8 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_ENTITLEMENTS = TunnelProv/TunnelProv.entitlements; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = SZ977XLF24; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = TunnelProv/Info.plist; - INFOPLIST_KEY_CFBundleDisplayName = TunnelProv; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - IPHONEOS_DEPLOYMENT_TARGET = 17.4; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@executable_path/../../Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.stik.sj.TunnelProv; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = iphoneos; - SKIP_INSTALL = YES; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - DC139F842DE97EA600F63846 /* Build configuration list for PBXNativeTarget "DebugWidgetExtension" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - DC139F822DE97EA600F63846 /* Debug */, - DC139F832DE97EA600F63846 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - DC6F1D322D94EADD0071B2B6 /* Build configuration list for PBXProject "StikDebug" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - DC6F1D5A2D94EADF0071B2B6 /* Debug */, - DC6F1D5B2D94EADF0071B2B6 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - DC6F1D5C2D94EADF0071B2B6 /* Build configuration list for PBXNativeTarget "StikDebug" */ = { - isa = XCConfigurationList; +DCA6901D2DAF660E007C91A8 /* Release */ = { +isa = XCBuildConfiguration; +buildSettings = { +CODE_SIGN_ENTITLEMENTS = TunnelProv/TunnelProv.entitlements; +CODE_SIGN_STYLE = Automatic; +CURRENT_PROJECT_VERSION = 1; +DEVELOPMENT_TEAM = SZ977XLF24; +GENERATE_INFOPLIST_FILE = YES; +INFOPLIST_FILE = TunnelProv/Info.plist; +INFOPLIST_KEY_CFBundleDisplayName = TunnelProv; +INFOPLIST_KEY_NSHumanReadableCopyright = ""; +IPHONEOS_DEPLOYMENT_TARGET = 17.4; +LD_RUNPATH_SEARCH_PATHS = ( +"$(inherited)", +"@executable_path/Frameworks", +"@executable_path/../../Frameworks", +); +MARKETING_VERSION = 1.0; +PRODUCT_BUNDLE_IDENTIFIER = com.stik.sj.TunnelProv; +PRODUCT_NAME = "$(TARGET_NAME)"; +SDKROOT = iphoneos; +SKIP_INSTALL = YES; +SWIFT_EMIT_LOC_STRINGS = YES; +SWIFT_VERSION = 5.0; +TARGETED_DEVICE_FAMILY = "1,2"; +VALIDATE_PRODUCT = YES; +}; +name = Release; +}; +D4AAA328FD7829CB8E395D8C /* Debug */ = { +isa = XCBuildConfiguration; +buildSettings = { +ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; +ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; +CLANG_ENABLE_MODULES = YES; +CODE_SIGN_ENTITLEMENTS = StikJIT/StikJIT.entitlements; +CODE_SIGN_STYLE = Automatic; +CURRENT_PROJECT_VERSION = 1; +DEVELOPMENT_ASSET_PATHS = "\"StikJIT/Preview Content\""; +DEVELOPMENT_TEAM = SZ977XLF24; +ENABLE_HARDENED_RUNTIME = YES; +ENABLE_PREVIEWS = YES; +GENERATE_INFOPLIST_FILE = YES; +INFOPLIST_FILE = StikJIT/StikVPNInfo.plist; +INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES; +"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES; +"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES; +"INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES; +"INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES; +"INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES; +"INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES; +"INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault; +"INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault; +INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; +INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; +INFOPLIST_KEY_UISupportsDocumentBrowser = YES; +IPHONEOS_DEPLOYMENT_TARGET = 17.4; +LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; +"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; +LIBRARY_SEARCH_PATHS = ( +"$(inherited)", +"$(PROJECT_DIR)/StikJIT/idevice", +); +MACOSX_DEPLOYMENT_TARGET = 15.1; +MARKETING_VERSION = 1.3.7; +PRODUCT_BUNDLE_IDENTIFIER = com.stik.StikVPN; +PRODUCT_NAME = "$(TARGET_NAME)"; +SDKROOT = auto; +SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator"; +SWIFT_EMIT_LOC_STRINGS = YES; +SWIFT_OBJC_BRIDGING_HEADER = "StikJIT/StikJIT-Bridging-Header.h"; +SWIFT_OPTIMIZATION_LEVEL = "-Onone"; +SWIFT_VERSION = 5.0; +TARGETED_DEVICE_FAMILY = "1,2,7"; +XROS_DEPLOYMENT_TARGET = 2.2; +}; +name = Debug; +}; +D4AAA329FD7829CB8E395D8D /* Release */ = { +isa = XCBuildConfiguration; +buildSettings = { +ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; +ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; +CLANG_ENABLE_MODULES = YES; +CODE_SIGN_ENTITLEMENTS = StikJIT/StikJIT.entitlements; +CODE_SIGN_STYLE = Automatic; +CURRENT_PROJECT_VERSION = 1; +DEVELOPMENT_ASSET_PATHS = "\"StikJIT/Preview Content\""; +DEVELOPMENT_TEAM = SZ977XLF24; +ENABLE_HARDENED_RUNTIME = YES; +ENABLE_PREVIEWS = YES; +GENERATE_INFOPLIST_FILE = YES; +INFOPLIST_FILE = StikJIT/StikVPNInfo.plist; +INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES; +"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES; +"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES; +"INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES; +"INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES; +"INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES; +"INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES; +"INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault; +"INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault; +INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; +INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; +INFOPLIST_KEY_UISupportsDocumentBrowser = YES; +IPHONEOS_DEPLOYMENT_TARGET = 17.4; +LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; +"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; +LIBRARY_SEARCH_PATHS = ( +"$(inherited)", +"$(PROJECT_DIR)/StikJIT/idevice", +); +MACOSX_DEPLOYMENT_TARGET = 15.1; +MARKETING_VERSION = 1.3.7; +PRODUCT_BUNDLE_IDENTIFIER = com.stik.StikVPN; +PRODUCT_NAME = "$(TARGET_NAME)"; +SDKROOT = auto; +SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator"; +SWIFT_EMIT_LOC_STRINGS = YES; +SWIFT_OBJC_BRIDGING_HEADER = "StikJIT/StikJIT-Bridging-Header.h"; +SWIFT_VERSION = 5.0; +TARGETED_DEVICE_FAMILY = "1,2,7"; +XROS_DEPLOYMENT_TARGET = 2.2; +}; +name = Release; +}; buildConfigurations = ( DC6F1D5D2D94EADF0071B2B6 /* Debug */, DC6F1D5E2D94EADF0071B2B6 /* Release */, @@ -933,33 +1068,21 @@ defaultConfigurationName = Release; }; DC6F1D5F2D94EADF0071B2B6 /* Build configuration list for PBXNativeTarget "StikDebugTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - DC6F1D602D94EADF0071B2B6 /* Debug */, - DC6F1D612D94EADF0071B2B6 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - DC6F1D622D94EADF0071B2B6 /* Build configuration list for PBXNativeTarget "StikDebugUITests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - DC6F1D632D94EADF0071B2B6 /* Debug */, - DC6F1D642D94EADF0071B2B6 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - DCA6901B2DAF660E007C91A8 /* Build configuration list for PBXNativeTarget "TunnelProv" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - DCA6901C2DAF660E007C91A8 /* Debug */, - DCA6901D2DAF660E007C91A8 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = DC6F1D2F2D94EADD0071B2B6 /* Project object */; -} +DCA6901B2DAF660E007C91A8 /* Build configuration list for PBXNativeTarget "TunnelProv" */ = { +isa = XCConfigurationList; +buildConfigurations = ( +DCA6901C2DAF660E007C91A8 /* Debug */, +DCA6901D2DAF660E007C91A8 /* Release */, +); +defaultConfigurationIsVisible = 0; +defaultConfigurationName = Release; +}; +D4AAA327FD7829CB8E395D8B /* Build configuration list for PBXNativeTarget "StikVPN" */ = { +isa = XCConfigurationList; +buildConfigurations = ( +D4AAA328FD7829CB8E395D8C /* Debug */, +D4AAA329FD7829CB8E395D8D /* Release */, +); +defaultConfigurationIsVisible = 0; +defaultConfigurationName = Release; +}; diff --git a/StikJIT/StikJITApp.swift b/StikJIT/StikJITApp.swift index 1d5bbd98..f4b94bc7 100644 --- a/StikJIT/StikJITApp.swift +++ b/StikJIT/StikJITApp.swift @@ -87,10 +87,10 @@ class TunnelManager: ObservableObject { static var shared = TunnelManager() private var vpnManager: NETunnelProviderManager? - private var tunnelDeviceIp: String { + var tunnelDeviceIp: String { UserDefaults.standard.string(forKey: "TunnelDeviceIP") ?? "10.7.0.0" } - private var tunnelFakeIp: String { + var tunnelFakeIp: String { UserDefaults.standard.string(forKey: "TunnelFakeIP") ?? "10.7.0.1" } private var tunnelSubnetMask: String { @@ -155,10 +155,16 @@ class TunnelManager: ObservableObject { switch connectionStatus { case .invalid, .disconnected: self.tunnelStatus = .disconnected + // Restart the heartbeat when the VPN disconnects so that + // debugging remains functional while browsing other tabs + startHeartbeatInBackground() case .connecting: self.tunnelStatus = .connecting case .connected: self.tunnelStatus = .connected + // Restart the heartbeat whenever the VPN reconnects to + // ensure debugging continues across view changes + startHeartbeatInBackground() case .disconnecting: self.tunnelStatus = .disconnecting case .reasserting: @@ -435,6 +441,7 @@ var pubHeartBeat = false @main struct HeartbeatApp: App { @AppStorage("hasLaunchedBefore") var hasLaunchedBefore: Bool = false + @AppStorage("autoStartVPN") private var autoStartVPN = true @State private var showWelcomeSheet: Bool = false @State private var isLoading2 = true @State private var isPairing = false @@ -543,8 +550,16 @@ struct HeartbeatApp: App { isLoading2 = false } } else if let vpn_error { - showAlert(title: "Error", message: "EM Proxy failed to connect: \(vpn_error)", showOk: true) { _ in - exit(0) + showAlert( + title: "Error", + message: "EM Proxy failed to connect: \(vpn_error)", + showOk: true, + primaryButtonText: "Continue", + showSecondaryButton: true, + secondaryButtonText: "Exit", + onSecondaryButtonTap: { exit(0) } + ) { _ in + isLoading2 = false } } } @@ -623,7 +638,7 @@ struct HeartbeatApp: App { // Otherwise, start the VPN automatically. if !hasLaunchedBefore { showWelcomeSheet = true - } else { + } else if autoStartVPN { TunnelManager.shared.startVPN() } } @@ -632,7 +647,9 @@ struct HeartbeatApp: App { // When the user taps "Continue", mark the app as launched and start the VPN. hasLaunchedBefore = true showWelcomeSheet = false - TunnelManager.shared.startVPN() + if autoStartVPN { + TunnelManager.shared.startVPN() + } } } } @@ -652,7 +669,7 @@ struct HeartbeatApp: App { } private func checkVPNConnection(callback: @escaping (Bool, String?) -> Void) { - let host = NWEndpoint.Host("10.7.0.1") + let host = NWEndpoint.Host(TunnelManager.shared.tunnelFakeIp) let port = NWEndpoint.Port(rawValue: 62078)! let connection = NWConnection(host: host, port: port, using: .tcp) var timeoutWorkItem: DispatchWorkItem? @@ -753,6 +770,7 @@ class MountingProgress: ObservableObject { mountingThread = Thread { let mountResult = mountPersonalDDI( + deviceIP: TunnelManager.shared.tunnelFakeIp, imagePath: URL.documentsDirectory.appendingPathComponent("DDI/Image.dmg").path, trustcachePath: URL.documentsDirectory.appendingPathComponent("DDI/Image.dmg.trustcache").path, manifestPath: URL.documentsDirectory.appendingPathComponent("DDI/BuildManifest.plist").path, @@ -795,6 +813,7 @@ func isPairing() -> Bool { func startHeartbeatInBackground() { let heartBeatThread = Thread { + setHeartbeatIP(TunnelManager.shared.tunnelFakeIp) let completionHandler: @convention(block) (Int32, String?) -> Void = { result, message in if result == 0 { print("Heartbeat started successfully: \(message ?? "")") @@ -923,7 +942,16 @@ struct LoadingView: View { } } -public func showAlert(title: String, message: String, showOk: Bool, showTryAgain: Bool = false, primaryButtonText: String? = nil, messageType: MessageType = .error, completion: @escaping (Bool) -> Void) { +public func showAlert(title: String, + message: String, + showOk: Bool, + showTryAgain: Bool = false, + primaryButtonText: String? = nil, + messageType: MessageType = .error, + showSecondaryButton: Bool = false, + secondaryButtonText: String? = nil, + onSecondaryButtonTap: (() -> Void)? = nil, + completion: @escaping (Bool) -> Void) { DispatchQueue.main.async { guard let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene else { return @@ -959,10 +987,16 @@ public func showAlert(title: String, message: String, showOk: Bool, showTryAgain }, showButton: true, primaryButtonText: primaryButtonText ?? "OK", + secondaryButtonText: secondaryButtonText ?? "Cancel", onPrimaryButtonTap: { rootViewController?.presentedViewController?.dismiss(animated: true) completion(true) }, + onSecondaryButtonTap: { + rootViewController?.presentedViewController?.dismiss(animated: true) + onSecondaryButtonTap?() + }, + showSecondaryButton: showSecondaryButton, messageType: messageType ) let hostingController = UIHostingController(rootView: customErrorView) diff --git a/StikJIT/StikVPNApp.swift b/StikJIT/StikVPNApp.swift new file mode 100644 index 00000000..1c855709 --- /dev/null +++ b/StikJIT/StikVPNApp.swift @@ -0,0 +1,10 @@ +import SwiftUI + +@main +struct StikVPNApp: App { + var body: some Scene { + WindowGroup { + StikVPNManagementView() + } + } +} diff --git a/StikJIT/StikVPNInfo.plist b/StikJIT/StikVPNInfo.plist new file mode 100644 index 00000000..dd41fa9e --- /dev/null +++ b/StikJIT/StikVPNInfo.plist @@ -0,0 +1,21 @@ + + + + + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLName + com.stik.StikJIT.enableJIT + CFBundleURLSchemes + + stikjit + + + + UIFileSharingEnabled + + + diff --git a/StikJIT/Utilities/mountDDI.swift b/StikJIT/Utilities/mountDDI.swift index 3cd06f9e..fb6f4dca 100644 --- a/StikJIT/Utilities/mountDDI.swift +++ b/StikJIT/Utilities/mountDDI.swift @@ -55,7 +55,7 @@ func isMounted() -> Bool { let pairingFilePath = URL.documentsDirectory.appendingPathComponent("pairingFile.plist").path - guard inet_pton(AF_INET, "10.7.0.1", &addr.sin_addr) == 1 else { + guard inet_pton(AF_INET, TunnelManager.shared.tunnelFakeIp, &addr.sin_addr) == 1 else { print("Invalid IP address") return false } @@ -115,7 +115,7 @@ func isMounted() -> Bool { } } -func mountPersonalDDI(deviceIP: String = "10.7.0.1", imagePath: String, trustcachePath: String, manifestPath: String, pairingFilePath: String) -> Int { +func mountPersonalDDI(deviceIP: String = TunnelManager.shared.tunnelFakeIp, imagePath: String, trustcachePath: String, manifestPath: String, pairingFilePath: String) -> Int { idevice_init_logger(Debug, Disabled, nil) print("Mounting \(imagePath) \(trustcachePath) \(manifestPath)") diff --git a/StikJIT/Views/MainTabView.swift b/StikJIT/Views/MainTabView.swift index 57b98f45..843c6ec0 100644 --- a/StikJIT/Views/MainTabView.swift +++ b/StikJIT/Views/MainTabView.swift @@ -6,6 +6,7 @@ // import SwiftUI +import NetworkExtension struct MainTabView: View { @AppStorage("customAccentColor") private var customAccentColorHex: String = "" @@ -24,6 +25,12 @@ struct MainTabView: View { .tabItem { Label("Home", systemImage: "house") } + + StikVPNManagementView() + .tabItem { + Label("StikVPN", systemImage: "lock.shield") + } + SettingsView() .tabItem { Label("Settings", systemImage: "gearshape.fill") @@ -33,3 +40,120 @@ struct MainTabView: View { .environment(\.accentColor, accentColor) } } + +struct StikVPNManagementView: View { + @ObservedObject private var tunnelManager = TunnelManager.shared + @AppStorage("customAccentColor") private var customAccentColorHex: String = "" + @AppStorage("autoStartVPN") private var autoStartVPN = true + @AppStorage("TunnelDeviceIP") private var deviceIP: String = "10.7.0.0" + @AppStorage("TunnelFakeIP") private var fakeIP: String = "10.7.0.1" + @Environment(\.colorScheme) private var colorScheme + + private var accentColor: Color { + if customAccentColorHex.isEmpty { + return .blue + } else { + return Color(hex: customAccentColorHex) ?? .blue + } + } + + var body: some View { + ZStack { + Color(UIColor.systemBackground) + .edgesIgnoringSafeArea(.all) + + VStack(spacing: 24) { + Spacer() + + VStack(spacing: 8) { + Text("StikVPN Status") + .font(.headline) + .foregroundColor(.secondary) + Text(tunnelManager.tunnelStatus.rawValue) + .font(.title) + .fontWeight(.bold) + } + + VStack(alignment: .leading, spacing: 12) { + Text("Device IP") + .font(.headline) + .foregroundColor(.secondary) + HStack { + TextField("10.7.0.0", text: $deviceIP) + .keyboardType(.numbersAndPunctuation) + .font(.body) + .foregroundColor(.primary) + .padding(.vertical, 8) + + if !deviceIP.isEmpty { + Button(action: { deviceIP = "" }) { + Image(systemName: "xmark.circle.fill") + .foregroundColor(Color(UIColor.tertiaryLabel)) + .font(.system(size: 16)) + } + } + } + .padding(.horizontal, 12) + .background(Color(UIColor.tertiarySystemFill)) + .cornerRadius(8) + + Text("Fake IP") + .font(.headline) + .foregroundColor(.secondary) + HStack { + TextField("10.7.0.1", text: $fakeIP) + .keyboardType(.numbersAndPunctuation) + .font(.body) + .foregroundColor(.primary) + .padding(.vertical, 8) + + if !fakeIP.isEmpty { + Button(action: { fakeIP = "" }) { + Image(systemName: "xmark.circle.fill") + .foregroundColor(Color(UIColor.tertiaryLabel)) + .font(.system(size: 16)) + } + } + } + .padding(.horizontal, 12) + .background(Color(UIColor.tertiarySystemFill)) + .cornerRadius(8) + } + .padding(.horizontal, 40) + + Button(action: toggleVPN) { + HStack { + Image(systemName: tunnelManager.tunnelStatus == .connected ? "xmark" : "checkmark") + .font(.system(size: 20)) + Text(tunnelManager.tunnelStatus == .connected ? "Disable StikVPN" : "Enable StikVPN") + .font(.system(.title3, design: .rounded)) + .fontWeight(.semibold) + } + .frame(maxWidth: .infinity) + .padding() + .background(accentColor) + .foregroundColor(accentColor.contrastText()) + .cornerRadius(16) + .shadow(color: accentColor.opacity(0.3), radius: 8, x: 0, y: 4) + } + .padding(.horizontal, 40) + + Toggle("Start StikVPN Automatically", isOn: $autoStartVPN) + .padding(.horizontal, 40) + + Spacer() + } + } + } + + private func toggleVPN() { + switch tunnelManager.tunnelStatus { + case .connected, .connecting: + tunnelManager.stopVPN() + case .disconnected, .error, .disconnecting: + tunnelManager.startVPN() + // Ensure the debugging heartbeat resumes when the VPN is enabled + startHeartbeatInBackground() + } + } +} diff --git a/StikJIT/Views/SettingsView.swift b/StikJIT/Views/SettingsView.swift index 518ee678..ff61ee09 100644 --- a/StikJIT/Views/SettingsView.swift +++ b/StikJIT/Views/SettingsView.swift @@ -536,7 +536,6 @@ struct SettingsView: View { } RunLoop.current.add(progressTimer, forMode: .common) - startHeartbeatInBackground() } catch { print("Error copying file: \(error)") diff --git a/StikJIT/idevice/heartbeat.c b/StikJIT/idevice/heartbeat.c index d2ee11a2..ef4e2c35 100644 --- a/StikJIT/idevice/heartbeat.c +++ b/StikJIT/idevice/heartbeat.c @@ -13,6 +13,13 @@ bool isHeartbeat = false; +static char heartbeat_ip[INET_ADDRSTRLEN] = "10.7.0.1"; + +void setHeartbeatIP(const char* ip) { + if (!ip) return; + strncpy(heartbeat_ip, ip, INET_ADDRSTRLEN - 1); + heartbeat_ip[INET_ADDRSTRLEN - 1] = '\0'; +} void startHeartbeat(IdevicePairingFile* pairing_file, TcpProviderHandle** provider, int* heartbeatSessionId, HeartbeatCompletionHandlerC completion, LogFuncC logger) { @@ -22,12 +29,12 @@ void startHeartbeat(IdevicePairingFile* pairing_file, TcpProviderHandle** provid struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; - if (inet_pton(AF_INET, "10.7.0.1", &addr.sin_addr) <= 0) { + if (inet_pton(AF_INET, heartbeat_ip, &addr.sin_addr) <= 0) { logger("DEBUG: Error converting IP address."); isHeartbeat = false; return; } - logger("DEBUG: Socket address created for IP 10.7.0.1"); + logger("DEBUG: Socket address created for IP %s", heartbeat_ip); IdeviceErrorCode err = IdeviceSuccess; diff --git a/StikJIT/idevice/heartbeat.h b/StikJIT/idevice/heartbeat.h index d1c026ac..82928ac7 100644 --- a/StikJIT/idevice/heartbeat.h +++ b/StikJIT/idevice/heartbeat.h @@ -16,5 +16,6 @@ typedef void (^LogFuncC)(const char* message, ...); extern bool isHeartbeat; void startHeartbeat(IdevicePairingFile* pairintFile, TcpProviderHandle** provider, int* heartbeatSessionId, HeartbeatCompletionHandlerC completion, LogFuncC logger); +void setHeartbeatIP(const char* ip); #endif /* HEARTBEAT_H */ diff --git a/TunnelProv/PacketTunnelProvider.swift b/TunnelProv/PacketTunnelProvider.swift index d6e6c174..632ea0d1 100644 --- a/TunnelProv/PacketTunnelProvider.swift +++ b/TunnelProv/PacketTunnelProvider.swift @@ -12,8 +12,10 @@ import Darwin class PacketTunnelProvider: NEPacketTunnelProvider { override func startTunnel(options: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) { - let deviceIP = options?["TunnelDeviceIP"] as? String ?? "10.7.0.0" - let fakeIP = options?["TunnelFakeIP"] as? String ?? "10.7.0.1" + let deviceIP = options?["TunnelDeviceIP"] as? String ?? + UserDefaults.standard.string(forKey: "TunnelDeviceIP") ?? "10.7.0.0" + let fakeIP = options?["TunnelFakeIP"] as? String ?? + UserDefaults.standard.string(forKey: "TunnelFakeIP") ?? "10.7.0.1" let toNetwork: (String) -> UInt32 = { address in var addr = in_addr()