Эх сурвалжийг харах

Hide the in-app back button on Reddit home and harden OAuth sign-in routing.

Co-authored-by: Cursor <cursoragent@cursor.com>
AhtashamShahzad1 1 сар өмнө
parent
commit
d95f3a47d9

+ 2 - 1
Reddit App/Managers/OAuthAuthenticationManager.swift

@@ -43,7 +43,8 @@ final class OAuthAuthenticationManager: NSObject {
         completion: @escaping (Result<URL, Error>) -> Void
     ) {
         guard !isAuthenticating else {
-            completion(.failure(OAuthError.alreadyInProgress))
+            // Reddit's Google/Apple buttons can fire both decidePolicyFor and
+            // createWebViewWith for the same OAuth URL; ignore the duplicate.
             return
         }
 

+ 37 - 13
Reddit App/Managers/RedditOAuthPanelController.swift

@@ -37,6 +37,7 @@ final class RedditOAuthPanelController: NSObject {
 
         let webView = WKWebView(frame: panel.contentView?.bounds ?? .zero, configuration: RedditWebViewManager.makeConfiguration())
         webView.navigationDelegate = self
+        webView.uiDelegate = self
         webView.autoresizingMask = [.width, .height]
         panel.contentView?.addSubview(webView)
 
@@ -62,6 +63,22 @@ final class RedditOAuthPanelController: NSObject {
         dismiss()
         completion?()
     }
+
+    private func beginOAuthSignIn(url: URL, in webView: WKWebView) {
+        OAuthAuthenticationManager.shared.authenticate(
+            url: url,
+            presentationWindow: panel
+        ) { [weak self] result in
+            guard let self else { return }
+            switch result {
+            case .success(let callbackURL):
+                webView.load(URLRequest(url: callbackURL))
+            case .failure(let error):
+                self.onAuthError?(error.localizedDescription)
+                self.finish()
+            }
+        }
+    }
 }
 
 extension RedditOAuthPanelController: WKNavigationDelegate {
@@ -85,19 +102,7 @@ extension RedditOAuthPanelController: WKNavigationDelegate {
 
         if RedditWebAuthHelper.isOAuthProviderURL(url) {
             decisionHandler(.cancel)
-            OAuthAuthenticationManager.shared.authenticate(
-                url: url,
-                presentationWindow: panel
-            ) { [weak self] result in
-                guard let self else { return }
-                switch result {
-                case .success(let callbackURL):
-                    webView.load(URLRequest(url: callbackURL))
-                case .failure(let error):
-                    self.onAuthError?(error.localizedDescription)
-                    self.finish()
-                }
-            }
+            beginOAuthSignIn(url: url, in: webView)
             return
         }
 
@@ -123,3 +128,22 @@ extension RedditOAuthPanelController: WKNavigationDelegate {
         return RedditWebAuthHelper.looksLikeLoggedInURL(url)
     }
 }
+
+extension RedditOAuthPanelController: WKUIDelegate {
+    func webView(
+        _ webView: WKWebView,
+        createWebViewWith configuration: WKWebViewConfiguration,
+        for navigationAction: WKNavigationAction,
+        windowFeatures: WKWindowFeatures
+    ) -> WKWebView? {
+        guard let url = navigationAction.request.url else { return nil }
+
+        if RedditWebAuthHelper.isOAuthProviderURL(url) {
+            beginOAuthSignIn(url: url, in: webView)
+            return nil
+        }
+
+        webView.load(URLRequest(url: url))
+        return nil
+    }
+}

+ 14 - 0
Reddit App/Utilities/RedditWebAuthHelper.swift

@@ -43,6 +43,20 @@ enum RedditWebAuthHelper {
         return false
     }
 
+    static func isRedditHomeURL(_ url: URL) -> Bool {
+        guard isRedditURL(url) else { return false }
+
+        let host = url.host?.lowercased() ?? ""
+        let isMainSite = host == "reddit.com"
+            || host == "www.reddit.com"
+            || host == "new.reddit.com"
+            || host == "old.reddit.com"
+        guard isMainSite else { return false }
+
+        let path = url.path.lowercased()
+        return path.isEmpty || path == "/" || path == "/home"
+    }
+
     static func isRedditURL(_ url: URL) -> Bool {
         guard let host = url.host?.lowercased() else { return false }
 

+ 5 - 1
Reddit App/ViewModels/FrontPageViewModel.swift

@@ -25,7 +25,11 @@ final class FrontPageViewModel {
         selectedNavItem = nil
         isRedditActive = true
         isSettingsActive = false
-        redditLoadURL = url ?? Self.redditHomeURL
+        let targetURL = url ?? Self.redditHomeURL
+        redditLoadURL = targetURL
+        if RedditWebAuthHelper.isRedditHomeURL(targetURL) {
+            redditCanGoBack = false
+        }
         redditReloadTrigger += 1
     }
 

+ 18 - 2
Reddit App/Views/RedditWebView.swift

@@ -53,6 +53,7 @@ struct RedditWebView: NSViewRepresentable {
         var lastLoadedURL: URL?
         private var prefillWorkItem: DispatchWorkItem?
         private var canGoBackObservation: NSKeyValueObservation?
+        private var urlObservation: NSKeyValueObservation?
         var onCanGoBackChange: (Bool) -> Void
         private let onAuthError: (String) -> Void
 
@@ -69,13 +70,25 @@ struct RedditWebView: NSViewRepresentable {
 
             canGoBackObservation = webView.observe(\.canGoBack, options: [.initial, .new]) { [weak self] webView, _ in
                 DispatchQueue.main.async {
-                    self?.onCanGoBackChange(webView.canGoBack)
+                    self?.reportBackButtonVisibility(for: webView)
+                }
+            }
+
+            urlObservation = webView.observe(\.url, options: [.new]) { [weak self] webView, _ in
+                DispatchQueue.main.async {
+                    self?.reportBackButtonVisibility(for: webView)
                 }
             }
         }
 
+        private func reportBackButtonVisibility(for webView: WKWebView) {
+            let isOnHome = webView.url.map(RedditWebAuthHelper.isRedditHomeURL) ?? false
+            onCanGoBackChange(webView.canGoBack && !isOnHome)
+        }
+
         func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
             startObservingNavigation(in: webView)
+            reportBackButtonVisibility(for: webView)
             webView.evaluateJavaScript(RedditPostBoundaryStyle.injectionScript, completionHandler: nil)
             webView.evaluateJavaScript(RedditHomeChromeStyle.injectionScript, completionHandler: nil)
             webView.evaluateJavaScript(RedditAuthChromeStyle.injectionScript, completionHandler: nil)
@@ -149,8 +162,11 @@ struct RedditWebView: NSViewRepresentable {
             }
 
             if RedditWebAuthHelper.isOAuthProviderURL(url) {
-                beginOAuthSignIn(url: url)
+                // Always route OAuth through ASWebAuthenticationSession. Reddit's login
+                // modal runs in a subframe; letting WebKit handle Google/Apple SSO there
+                // triggers SOAuthorizationCoordinator subframe errors and breaks sign-in.
                 decisionHandler(.cancel)
+                beginOAuthSignIn(url: url)
                 return
             }