Parcourir la source

Use separate window for Zoom OAuth and improve web session sync.

Open sign-in in InAppOAuthWindowController instead of the embedded panel,
prime the meeting web view after OAuth and on home load, and route signed-in
zoom.us links through the shared WKWebView for cookie continuity.

Co-authored-by: Cursor <cursoragent@cursor.com>
huzaifahayat12 il y a 2 mois
Parent
commit
9a26bd1695
1 fichiers modifiés avec 27 ajouts et 20 suppressions
  1. 27 20
      zoom_app/ViewController.swift

+ 27 - 20
zoom_app/ViewController.swift

@@ -749,21 +749,8 @@ class ViewController: NSViewController {
         ensureUsageSessionStartDate()
         scheduleUsageBasedRatingPromptIfNeeded()
         recordedMeetings = MeetingRecordingManager.shared.recordings
-        zoomOAuth.embeddedOAuthSession = { [weak self] startURL, callbackPrefix, timeout in
-            guard let self else { throw ZoomOAuthError.unableToOpenBrowser }
-            do {
-                return try await self.runEmbeddedOAuthSession(
-                    startURL: startURL,
-                    callbackURLPrefix: callbackPrefix,
-                    timeoutSeconds: timeout
-                )
-            } catch EmbeddedOAuthFlowError.userCancelled {
-                throw ZoomOAuthError.authenticationCancelled
-            } catch EmbeddedOAuthFlowError.timedOut {
-                throw ZoomOAuthError.authenticationTimedOut
-            } catch EmbeddedOAuthFlowError.webViewUnavailable {
-                throw ZoomOAuthError.unableToOpenBrowser
-            }
+        zoomOAuth.onInteractiveSignInCompleted = { [weak self] in
+            self?.primeZoomEmbeddedWebSession()
         }
         NotificationCenter.default.addObserver(
             forName: MeetingRecordingManager.recordingsDidChangeNotification,
@@ -974,6 +961,9 @@ class ViewController: NSViewController {
         applyAuthenticationUIState(triggerInitialRefresh: refreshMeetings)
         updateHomeSidebarHighlight()
         updateSelectedHomeSectionUI()
+        if isUserLoggedIn() {
+            primeZoomEmbeddedWebSession()
+        }
     }
 
     private func isUserLoggedIn() -> Bool {
@@ -1050,7 +1040,6 @@ class ViewController: NSViewController {
                         UserDefaults.standard.set(profileTimeZone.identifier, forKey: Self.zoomAccountTimeZoneDefaultsKey)
                     }
                     self.completeLoginAndRestart(profile: profile)
-                    self.primeZoomEmbeddedWebSession()
                 }
             } catch {
                 await MainActor.run {
@@ -2368,8 +2357,17 @@ class ViewController: NSViewController {
         joinZoomMeetingFromLink(url.absoluteString, displayName: meeting.title)
     }
 
+    /// True for zoom.us / app.zoom.us pages (not API hosts). When signed in, these load in the shared embedded browser so OAuth cookies apply.
+    private func isZoomWebsiteURL(_ url: URL) -> Bool {
+        guard let host = url.host?.lowercased(), host.contains("zoom.") else { return false }
+        if host.hasPrefix("api.") { return false }
+        let path = url.path.lowercased()
+        if path.hasPrefix("/oauth") { return false }
+        return true
+    }
+
     /// Opens Zoom meeting join/start links in the right-panel `WKWebView` (same store as embedded Zoom OAuth).
-    /// Other URLs open in the system default browser.
+    /// Other zoom.us pages open in that web view when signed in; everything else uses the system browser.
     /// For Zoom meeting join/start links, asks for recording consent first, persists transcription languages from that sheet,
     /// then optionally begins local audio recording (when the user allows and recording is not already active).
     @MainActor
@@ -2389,8 +2387,10 @@ class ViewController: NSViewController {
             shouldRecordLocally = false
         }
 
+        let useEmbeddedBrowser = embeddedBrowserWebView != nil
+            && (isZoomMeetingJoinOrStartURL(targetURL) || (isUserLoggedIn() && isZoomWebsiteURL(targetURL)))
         let opened: Bool
-        if isZoomMeetingJoinOrStartURL(targetURL), embeddedBrowserWebView != nil {
+        if useEmbeddedBrowser {
             presentURLInEmbeddedRightPanel(targetURL)
             opened = true
         } else {
@@ -3354,6 +3354,7 @@ class ViewController: NSViewController {
         let trimmedName = profile?.name?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
         zoomSignedInDisplayName = trimmedName.isEmpty ? nil : trimmedName
         showHomeView(profile: profile)
+        primeZoomEmbeddedWebSession()
         if let window = view.window {
             window.makeKeyAndOrderFront(nil)
         }
@@ -10644,10 +10645,14 @@ final class ZoomOAuthService: NSObject {
     static let shared = ZoomOAuthService()
     private var inAppOAuthWindowController: InAppOAuthWindowController?
 
-    /// When set (by `ViewController`), Zoom OAuth runs in the right-panel web view so cookies match embedded meetings.
+    /// When set, Zoom OAuth runs in this session instead of a separate window (unused; sign-in uses `InAppOAuthWindowController`).
     @MainActor
     var embeddedOAuthSession: (@MainActor (URL, String, Double) async throws -> URL)?
 
+    /// Called after a successful interactive OAuth flow (separate sign-in window).
+    @MainActor
+    var onInteractiveSignInCompleted: (() -> Void)?
+
     private let tokenStore = ZoomOAuthTokenStore()
     private let clientIdDefaultsKey = "zoom.oauth.clientId"
     private let clientSecretDefaultsKey = "zoom.oauth.clientSecret"
@@ -10803,7 +10808,9 @@ final class ZoomOAuthService: NSObject {
             guard let code = queryItems?.first(where: { $0.name == "code" })?.value, code.isEmpty == false else {
                 throw ZoomOAuthError.missingAuthorizationCode
             }
-            return try await exchangeCodeForTokens(code: code, redirectURI: redirectURI, clientId: clientId, clientSecret: clientSecret)
+            let tokens = try await exchangeCodeForTokens(code: code, redirectURI: redirectURI, clientId: clientId, clientSecret: clientSecret)
+            await MainActor.run { self.onInteractiveSignInCompleted?() }
+            return tokens
         } catch GoogleOAuthError.authenticationTimedOut {
             throw ZoomOAuthError.authenticationTimedOut
         } catch GoogleOAuthError.authenticationCancelled {