From 6b71ed5f0668df94d4bdb938c20d699a4cf051e9 Mon Sep 17 00:00:00 2001 From: Jackson Coxson Date: Sat, 29 Mar 2025 13:35:02 -0600 Subject: [PATCH 1/3] Add VPN check before heartbeat --- StikJIT/StikJITApp.swift | 103 +++++++++++++++++++++++++++++++++------ 1 file changed, 88 insertions(+), 15 deletions(-) diff --git a/StikJIT/StikJITApp.swift b/StikJIT/StikJITApp.swift index ce72c82..5183294 100644 --- a/StikJIT/StikJITApp.swift +++ b/StikJIT/StikJITApp.swift @@ -6,6 +6,7 @@ // import SwiftUI +import Network import em_proxy import UniformTypeIdentifiers @@ -44,26 +45,41 @@ struct HeartbeatApp: App { .onAppear { startProxy() { result, error in if result { - if FileManager.default.fileExists(atPath: URL.documentsDirectory.appendingPathComponent("pairingFile.plist").path) { - Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { timer in - if pubHeartBeat { - isLoading = false - timer.invalidate() - } else { - if let error { - if error == InvalidHostID.rawValue { - isPairing = true + checkVPNConnection() { result, vpn_error in + if result { + if FileManager.default.fileExists(atPath: URL.documentsDirectory.appendingPathComponent("pairingFile.plist").path) { + Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { timer in + if pubHeartBeat { + isLoading = false + timer.invalidate() } else { - startHeartbeatInBackground() + if let error { + if error == InvalidHostID.rawValue { + isPairing = true + } else { + startHeartbeatInBackground() + } + self.error = nil + } } - self.error = nil } + + startHeartbeatInBackground() + } else { + isLoading = false + } + } else if let vpn_error { + showAlert(title: "Error", message: "EM Proxy failed to connect: \(vpn_error)", showOk: true) { _ in + // Add code here to exit the application + exit(0) // This will terminate the app immediately + + // Or for a more graceful exit in iOS: + // UIApplication.shared.perform(#selector(NSXPCConnection.suspend)) + // DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + // exit(0) + // } } } - - startHeartbeatInBackground() - } else { - isLoading = false } } else if let error { showAlert(title: "Error", message: "EM Proxy Failed to start \(error)", showOk: true) { cool in @@ -137,6 +153,63 @@ struct HeartbeatApp: App { } } } + + private func checkVPNConnection(callback: @escaping (Bool, String?) -> Void) { + let host = NWEndpoint.Host("10.7.0.1") + let port = NWEndpoint.Port(rawValue: 62078)! + + let connection = NWConnection(host: host, port: port, using: .tcp) + + // Create a variable to hold the timeout work item + var timeoutWorkItem: DispatchWorkItem? + + timeoutWorkItem = DispatchWorkItem { [weak connection] in + if connection?.state != .ready { + connection?.cancel() + DispatchQueue.main.async { + // Only call back if we haven't already + if timeoutWorkItem?.isCancelled == false { + callback(false, "[TIMEOUT] Wireguard is not connected. Try closing this app, turn Wireguard off and back on.") + } + } + } + } + + connection.stateUpdateHandler = { [weak connection] state in + switch state { + case .ready: + // Connection succeeded - cancel the timeout + timeoutWorkItem?.cancel() + connection?.cancel() + DispatchQueue.main.async { + callback(true, nil) + } + case .failed(let error): + // Connection failed - cancel the timeout + timeoutWorkItem?.cancel() + connection?.cancel() + DispatchQueue.main.async { + if error == NWError.posix(.ETIMEDOUT) { + callback(false, "Wireguard is not connected. Try closing the app, turn it off and back on.") + } else if error == NWError.posix(.ECONNREFUSED) { + callback(false, "Wifi is not connected. StikJIT won't work on cellular data.") + } else { + callback(false, "em proxy check error: \(error.localizedDescription)") + } + } + default: + break + } + } + + // Start the connection + connection.start(queue: .global()) + + // Schedule the timeout + if let workItem = timeoutWorkItem { + DispatchQueue.global().asyncAfter(deadline: .now() + 10, execute: workItem) + } + } } var pubHeartBeat = false From 3af58ae846c7726a61b0e815d5d634b6aba3b035 Mon Sep 17 00:00:00 2001 From: Jackson Coxson Date: Sat, 29 Mar 2025 13:38:49 -0600 Subject: [PATCH 2/3] Increase em proxy timeout --- StikJIT/StikJITApp.swift | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/StikJIT/StikJITApp.swift b/StikJIT/StikJITApp.swift index 5183294..61dc67d 100644 --- a/StikJIT/StikJITApp.swift +++ b/StikJIT/StikJITApp.swift @@ -70,14 +70,7 @@ struct HeartbeatApp: App { } } else if let vpn_error { showAlert(title: "Error", message: "EM Proxy failed to connect: \(vpn_error)", showOk: true) { _ in - // Add code here to exit the application - exit(0) // This will terminate the app immediately - - // Or for a more graceful exit in iOS: - // UIApplication.shared.perform(#selector(NSXPCConnection.suspend)) - // DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { - // exit(0) - // } + exit(0) } } } @@ -207,7 +200,7 @@ struct HeartbeatApp: App { // Schedule the timeout if let workItem = timeoutWorkItem { - DispatchQueue.global().asyncAfter(deadline: .now() + 10, execute: workItem) + DispatchQueue.global().asyncAfter(deadline: .now() + 20, execute: workItem) } } } From b3c0cc6e45e38d617020b831704d8a38c06516c2 Mon Sep 17 00:00:00 2001 From: Jackson Coxson Date: Sat, 29 Mar 2025 13:41:43 -0600 Subject: [PATCH 3/3] Check for Wifi before continuing --- StikJIT/StikJITApp.swift | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/StikJIT/StikJITApp.swift b/StikJIT/StikJITApp.swift index 61dc67d..8a1ea00 100644 --- a/StikJIT/StikJITApp.swift +++ b/StikJIT/StikJITApp.swift @@ -43,6 +43,14 @@ struct HeartbeatApp: App { if isLoading { LoadingView() .onAppear { + if !isConnectedToWifi() { + showAlert(title: "Connection Required", + message: "Please connect to WiFi to continue", + showOk: true) { _ in + exit(0) + } + return + } startProxy() { result, error in if result { checkVPNConnection() { result, vpn_error in @@ -203,6 +211,27 @@ struct HeartbeatApp: App { DispatchQueue.global().asyncAfter(deadline: .now() + 20, execute: workItem) } } + + func isConnectedToWifi() -> Bool { + var isWifi = false + let monitor = NWPathMonitor(requiredInterfaceType: .wifi) + let semaphore = DispatchSemaphore(value: 0) + + monitor.pathUpdateHandler = { path in + isWifi = path.status == .satisfied + semaphore.signal() + } + + let queue = DispatchQueue(label: "WiFiCheckQueue") + monitor.start(queue: queue) + + // Wait for the result with a timeout to avoid hanging + let result = semaphore.wait(timeout: .now() + 2) + monitor.cancel() + + // Return false if we timed out + return result == .success && isWifi + } } var pubHeartBeat = false