diff --git a/firefox-ios/Client/Frontend/Browser/BrowserViewController/Extensions/BrowserViewController+WebViewDelegates.swift b/firefox-ios/Client/Frontend/Browser/BrowserViewController/Extensions/BrowserViewController+WebViewDelegates.swift index c96845bec72e..7558ebb130ec 100644 --- a/firefox-ios/Client/Frontend/Browser/BrowserViewController/Extensions/BrowserViewController+WebViewDelegates.swift +++ b/firefox-ios/Client/Frontend/Browser/BrowserViewController/Extensions/BrowserViewController+WebViewDelegates.swift @@ -35,6 +35,18 @@ extension BrowserViewController: WKUIDelegate { return nil } + let navigationUrl = navigationAction.request.url + let navigationUrlString = navigationUrl?.absoluteString ?? "" + + // Check for "data" scheme using WebViewNavigationHandlerImplementation + let navigationHandler = WebViewNavigationHandlerImplementation { _ in } + var shouldAllowDataScheme = true + if navigationHandler.shouldFilterDataScheme(url: navigationUrl) { + shouldAllowDataScheme = navigationHandler.shouldAllowDataScheme(for: navigationUrl) + } + + guard shouldAllowDataScheme else { return nil } + // If the page uses `window.open()` or `[target="_blank"]`, open the page in a new tab. // IMPORTANT!!: WebKit will perform the `URLRequest` automatically!! Attempting to do // the request here manually leads to incorrect results!! @@ -44,7 +56,7 @@ extension BrowserViewController: WKUIDelegate { configuration: configuration ) - if navigationAction.request.url == nil { + if navigationUrl == nil || navigationUrlString.isEmpty { newTab.url = URL(string: "about:blank") } diff --git a/firefox-ios/Client/Frontend/Browser/WebView/WebViewNavigationHandler.swift b/firefox-ios/Client/Frontend/Browser/WebView/WebViewNavigationHandler.swift index 786ff92c4dae..0c5ef7af6dc9 100644 --- a/firefox-ios/Client/Frontend/Browser/WebView/WebViewNavigationHandler.swift +++ b/firefox-ios/Client/Frontend/Browser/WebView/WebViewNavigationHandler.swift @@ -11,7 +11,7 @@ protocol WebViewNavigationHandler { /// Whether we should filter that URL for data scheme or not /// - Returns: True when the URL needs to be filtered for the data scheme - func shouldFilterDataScheme(url: URL) -> Bool + func shouldFilterDataScheme(url: URL?) -> Bool /// Filter top-level data scheme has defined in: /// https://blog.mozilla.org/security/2017/11/27/blocking-top-level-navigations-data-urls-firefox-59/ @@ -38,7 +38,8 @@ struct WebViewNavigationHandlerImplementation: WebViewNavigationHandler { self.decisionHandler = decisionHandler } - func shouldFilterDataScheme(url: URL) -> Bool { + func shouldFilterDataScheme(url: URL?) -> Bool { + guard let url else { return false } return url.scheme == WebViewNavigationHandlerImplementation.Scheme.data.rawValue } @@ -51,32 +52,39 @@ struct WebViewNavigationHandlerImplementation: WebViewNavigationHandler { return } - let url = url.absoluteString.lowercased() - // Allow certain image types - if url.hasPrefix("data:image/") && !url.hasPrefix("data:image/svg+xml") { + if shouldAllowDataScheme(for: url) { decisionHandler(.allow) - return + } else { + decisionHandler(.cancel) + } + } + + func shouldAllowDataScheme(for url: URL?) -> Bool { + guard let url else { return false } + let urlString = url.absoluteString.lowercased() + + // Allow certain image types + if urlString.hasPrefix("data:image/") && !urlString.hasPrefix("data:image/svg+xml") { + return true } // Allow video, and certain application types - if url.hasPrefix("data:video/") - || url.hasPrefix("data:application/pdf") - || url.hasPrefix("data:application/json") { - decisionHandler(.allow) - return + if urlString.hasPrefix("data:video/") + || urlString.hasPrefix("data:application/pdf") + || urlString.hasPrefix("data:application/json") { + return true } // Allow plain text types. - // Note the format of data URLs is `data:[][;base64],` + // Note the format of data URLs is `data:[][;base64],` // with empty indicating plain text. - if url.hasPrefix("data:;base64,") - || url.hasPrefix("data:,") - || url.hasPrefix("data:text/plain,") - || url.hasPrefix("data:text/plain;") { - decisionHandler(.allow) - return + if urlString.hasPrefix("data:;base64,") + || urlString.hasPrefix("data:,") + || urlString.hasPrefix("data:text/plain,") + || urlString.hasPrefix("data:text/plain;") { + return true } - decisionHandler(.cancel) + return false } } diff --git a/firefox-ios/Client/TabManagement/Legacy/LegacyTabManager.swift b/firefox-ios/Client/TabManagement/Legacy/LegacyTabManager.swift index 1adbacc3bfdd..ed16f8232961 100644 --- a/firefox-ios/Client/TabManagement/Legacy/LegacyTabManager.swift +++ b/firefox-ios/Client/TabManagement/Legacy/LegacyTabManager.swift @@ -408,7 +408,6 @@ class LegacyTabManager: NSObject, FeatureFlaggable, TabManager, TabEventHandler let popup = Tab(profile: profile, isPrivate: parentTab.isPrivate, windowUUID: windowUUID) - // Configure the tab for the child popup webview. In this scenario we need to be sure to pass along // the specific `configuration` that we are given by the WKUIDelegate callback, since if we do not // use this configuration WebKit will throw an exception.