From e6fd5e31e6b573eaeec5d9df9cb8d7545e4d693e Mon Sep 17 00:00:00 2001 From: Albert Koch Date: Tue, 7 Nov 2023 13:41:05 -0800 Subject: [PATCH] Add new NetworkMonitor and reload webview on network changes --- XCreds/WebViewWindowController.swift | 30 ++++++-- .../LoginWebViewWindowController.swift | 19 +---- .../LoginWindow/NetworkMonitor.swift | 72 +++++++++++++++++++ .../Mechanisms/XCredsLoginMechanism.swift | 43 +---------- xCreds.xcodeproj/project.pbxproj | 8 ++- 5 files changed, 107 insertions(+), 65 deletions(-) create mode 100644 XCredsLoginPlugIn/LoginWindow/NetworkMonitor.swift diff --git a/XCreds/WebViewWindowController.swift b/XCreds/WebViewWindowController.swift index a53a88d6..ab7f6a35 100644 --- a/XCreds/WebViewWindowController.swift +++ b/XCreds/WebViewWindowController.swift @@ -53,13 +53,17 @@ class WebViewWindowController: NSWindowController { return } - TCSLogWithMark() - if let url = TokenManager.shared.oidc().createLoginURL() { + + NotificationCenter.default.addObserver(self, selector: #selector(connectivityStatusHandler(notification:)), name: NSNotification.Name.connectivityStatus, object: nil) + NetworkMonitor.shared.startMonitoring() + if let url = getOidcLoginURL() { TCSLogWithMark() self.webView.load(URLRequest(url: url)) + NetworkMonitor.shared.stopMonitoring() } else { - TCSLogWithMark() + TCSLogWithMark("Failed to get URL") + TCSLogWithMark("Network monitor: adding connectivity status change observer") let allBundles = Bundle.allBundles for currentBundle in allBundles { if currentBundle.bundlePath.contains("XCreds") { @@ -68,12 +72,30 @@ class WebViewWindowController: NSWindowController { self.webView.load(URLRequest(url:loadPageURL)) } break - } } } } + @objc func connectivityStatusHandler(notification: Notification) { + TCSLogWithMark("Network monitor: handling connectivity status update") + if NetworkMonitor.shared.isConnected { + TCSLogWithMark("Refresh webview login") + self.loadPage() + } + } + + private func getOidcLoginURL() -> URL? { + for _ in 1...5 { + if let url = TokenManager.shared.oidc().createLoginURL() { + return url + } + TCSLogWithMark("Trying to get login url again") + Thread.sleep(forTimeInterval: 1) + } + return nil + } + @IBAction func clickCancel(_ sender: Any) { self.window?.close() } diff --git a/XCredsLoginPlugIn/LoginWindow/LoginWebViewWindowController.swift b/XCredsLoginPlugIn/LoginWindow/LoginWebViewWindowController.swift index 425ee083..5b6a04ba 100644 --- a/XCredsLoginPlugIn/LoginWindow/LoginWebViewWindowController.swift +++ b/XCredsLoginPlugIn/LoginWindow/LoginWebViewWindowController.swift @@ -42,7 +42,6 @@ class LoginWebViewWindowController: WebViewWindowController { for currentBundle in allBundles { TCSLogWithMark(currentBundle.bundlePath) if currentBundle.bundlePath.contains("XCreds") { - controlsViewController = ControlsViewController.init(nibName: NSNib.Name("ControlsViewController"), bundle: currentBundle) if let controlsViewController = controlsViewController { self.window?.contentView?.addSubview(controlsViewController.view) @@ -54,33 +53,17 @@ class LoginWebViewWindowController: WebViewWindowController { else { TCSLogWithMark("controlsViewController nil") } - } } - TCSLogWithMark() - networkChangeObserver = NotificationCenter.default.addObserver(forName:NSNotification.Name("NetworkChanged"), object: nil, queue: nil) { notification in - // TCSLogWithMark("network changed.") - let userInfo = notification.userInfo as? [String:Bool] - if let userInfo = userInfo, let networkStatus = userInfo["online"], networkStatus==true { - self.loadPage() - } - } - - resolutionObserver = NotificationCenter.default.addObserver(forName:NSApplication.didChangeScreenParametersNotification, object: nil, queue: nil) { notification in TCSLogWithMark("Resolution changed. Resetting size") - self.setupLoginWindowAppearance() - } + TCSLogWithMark("loading webview for login") setupLoginWindowAppearance() - TCSLogWithMark("loading page") - - - loadPage() } diff --git a/XCredsLoginPlugIn/LoginWindow/NetworkMonitor.swift b/XCredsLoginPlugIn/LoginWindow/NetworkMonitor.swift new file mode 100644 index 00000000..d66d54fc --- /dev/null +++ b/XCredsLoginPlugIn/LoginWindow/NetworkMonitor.swift @@ -0,0 +1,72 @@ +// +// NetworkMonitor.swift +// XCredsLoginPlugin +// +// Created by Carlos Hernandez on 2023-10-22. +// + +import Foundation +import Network + +extension Notification.Name { + static let connectivityStatus = Notification.Name(rawValue: "connectivityStatusChanged") +} + +extension NWInterface.InterfaceType: CaseIterable { + public static var allCases: [NWInterface.InterfaceType] = [ + .other, + .wifi, + .cellular, + .loopback, + .wiredEthernet + ] +} + +final class NetworkMonitor { + static let shared = NetworkMonitor() + + private let queue = DispatchQueue(label: "NetworkConnectivityMonitor") + private let monitor: NWPathMonitor + + private(set) var isConnected = false + private(set) var isExpensive = false + private(set) var lastNotification: Date? + private(set) var currentConnectionType: NWInterface.InterfaceType? + + private init() { + monitor = NWPathMonitor(prohibitedInterfaceTypes: [.cellular, .loopback]) + } + + func startMonitoring() { + monitor.pathUpdateHandler = { [weak self] path in + TCSLogWithMark("Network monitor: path updated") + self?.isConnected = path.status == .satisfied + self?.isExpensive = path.isExpensive + self?.currentConnectionType = NWInterface.InterfaceType.allCases.filter { path.usesInterfaceType($0) }.first + if WifiManager().isConnectedToNetwork() == true { + TCSLogWithMark("Network monitor: connected to network") + if let lastNotification = self?.lastNotification { + if abs(lastNotification.timeIntervalSinceNow) > 5 { + TCSLogWithMark("Network monitor: posting connectivity status to NC: \(path.status) for \(String(describing: self?.currentConnectionType))") + self?.lastNotification = Date() + NotificationCenter.default.post(name: .connectivityStatus, object: nil) + } else { + TCSLogWithMark("Network monitor: debouncing connectivity status to NC") + } + } else { + TCSLogWithMark("Network monitor: posting connectivity status to NC: \(path.status) for \(String(describing: self?.currentConnectionType))") + self?.lastNotification = Date() + NotificationCenter.default.post(name: .connectivityStatus, object: nil) + } + } else { + TCSLogWithMark("Not connected to network, no notfication posted") + } + } + monitor.start(queue: queue) + } + + func stopMonitoring() { + TCSLogWithMark("Network monitor: stopping") + monitor.cancel() + } +} diff --git a/XCredsLoginPlugIn/Mechanisms/XCredsLoginMechanism.swift b/XCredsLoginPlugIn/Mechanisms/XCredsLoginMechanism.swift index f7808fe5..a6150140 100644 --- a/XCredsLoginPlugIn/Mechanisms/XCredsLoginMechanism.swift +++ b/XCredsLoginPlugIn/Mechanisms/XCredsLoginMechanism.swift @@ -2,6 +2,7 @@ import Cocoa import Network + @objc class XCredsLoginMechanism: XCredsBaseMechanism { // @objc var loginWindow: XCredsLoginMechanism! var loginWebViewWindowController: LoginWebViewWindowController? @@ -15,7 +16,6 @@ import Network } let checkADLog = "checkADLog" var loginWindowType = LoginWindowType.cloud - let monitor = NWPathMonitor() override init(mechanism: UnsafePointer) { let allBundles = Bundle.allBundles @@ -172,44 +172,6 @@ import Network showLoginWindowType(loginWindowType: .usernamePassword) } } - func startNetworkMonitoring(){ - monitor.pathUpdateHandler = { path in - - TCSLogWithMark("network changed. \(path.debugDescription)") - if path.status != .satisfied { - TCSLogErrorWithMark("not connected") - } - else if path.usesInterfaceType(.cellular) { - TCSLogWithMark("Cellular") - } - else if path.usesInterfaceType(.wifi) { - TCSLogWithMark("Wifi changed") - } - else if path.usesInterfaceType(.wiredEthernet) { - TCSLogWithMark("Ethernet") - } - else if path.usesInterfaceType(.other){ - TCSLogWithMark("Other") - } - else if path.usesInterfaceType(.loopback){ - TCSLogWithMark("Loop Back") - } - else { - TCSLogWithMark("Unknown interface type") - } - self.selectAndShowLoginWindow() - TCSLogWithMark("network changed") - NotificationCenter.default.post(name: NSNotification.Name("NetworkChanged"), object: self, userInfo: ["online":path.status == .satisfied]) - - } - let queue = DispatchQueue(label: "Monitor") - monitor.start(queue: queue) - } - func stopNetworkMonitoring() { - monitor.cancel() - monitor.pathUpdateHandler=nil - - } @objc override func run() { TCSLogWithMark("XCredsLoginMechanism mech starting") if useAutologin() { @@ -257,7 +219,6 @@ import Network } override func allowLogin() { - stopNetworkMonitoring() TCSLogWithMark("Allowing Login") if loginWebViewWindowController != nil { @@ -268,7 +229,6 @@ import Network super.allowLogin() } override func denyLogin(message:String?) { - stopNetworkMonitoring() // loginWindowControlsWindowController.close() loginWebViewWindowController?.loadPage() TCSLog("***************** DENYING LOGIN FROM LOGIN MECH ********************"); @@ -303,6 +263,7 @@ import Network loginWebViewWindowController.window?.makeKeyAndOrderFront(self) case .usernamePassword: + NetworkMonitor.shared.stopMonitoring() if loginWebViewWindowController != nil { loginWebViewWindowController?.window?.orderOut(self) diff --git a/xCreds.xcodeproj/project.pbxproj b/xCreds.xcodeproj/project.pbxproj index 809504bd..a854e2ba 100644 --- a/xCreds.xcodeproj/project.pbxproj +++ b/xCreds.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 081904872AFAE61800F7DA33 /* NetworkMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 081904862AFAE61800F7DA33 /* NetworkMonitor.swift */; }; 760418D12A1332210051411B /* SignIn.xib in Resources */ = {isa = PBXBuildFile; fileRef = 760418CE2A1332210051411B /* SignIn.xib */; }; 760418D22A1332210051411B /* SignInWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 760418CF2A1332210051411B /* SignInWindowController.swift */; }; 760418D52A1332520051411B /* DS+AD.swift in Sources */ = {isa = PBXBuildFile; fileRef = 760418D42A1332520051411B /* DS+AD.swift */; }; @@ -279,6 +280,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 081904862AFAE61800F7DA33 /* NetworkMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = NetworkMonitor.swift; path = XCredsLoginPlugIn/LoginWindow/NetworkMonitor.swift; sourceTree = ""; }; 760418CE2A1332210051411B /* SignIn.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SignIn.xib; sourceTree = ""; }; 760418CF2A1332210051411B /* SignInWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignInWindowController.swift; sourceTree = ""; }; 760418D42A1332520051411B /* DS+AD.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DS+AD.swift"; sourceTree = ""; }; @@ -638,6 +640,7 @@ 76EE069127FD1D00009E0F3A = { isa = PBXGroup; children = ( + 081904862AFAE61800F7DA33 /* NetworkMonitor.swift */, 7681FEC82A4CFEA200F91CD1 /* com.twocanoes.xcreds.plist */, 76C63A312A22872700810C53 /* History.md */, 760418CC2A1331710051411B /* NomadLogin */, @@ -902,7 +905,7 @@ }; }; }; - buildConfigurationList = 76EE069527FD1D00009E0F3A /* Build configuration list for PBXProject "XCreds" */; + buildConfigurationList = 76EE069527FD1D00009E0F3A /* Build configuration list for PBXProject "xCreds" */; compatibilityVersion = "Xcode 13.0"; developmentRegion = en; hasScannedForEncodings = 0; @@ -1016,6 +1019,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 081904872AFAE61800F7DA33 /* NetworkMonitor.swift in Sources */, 7632E3A32873581100E37923 /* KeychainUtil.swift in Sources */, 76B882AB29CCFD7A00BB8186 /* TCSKeychain.m in Sources */, 76BEF7DD2871F5F00013E2A1 /* TCSReturnWindow.m in Sources */, @@ -1699,7 +1703,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 76EE069527FD1D00009E0F3A /* Build configuration list for PBXProject "XCreds" */ = { + 76EE069527FD1D00009E0F3A /* Build configuration list for PBXProject "xCreds" */ = { isa = XCConfigurationList; buildConfigurations = ( 76EE06A527FD1D01009E0F3A /* Debug */,