Skip to content
This repository has been archived by the owner on May 10, 2024. It is now read-only.

Commit

Permalink
Fix #4358: Add support for downloading mobileconfig (#8245)
Browse files Browse the repository at this point in the history
This change also:
- Adjusts the iCal link downloading to use check the mime type in the instances where an `ics` file may be returned by the server without a path extension but a valid mime type in the response headers.
- Removes empty tabs that are left open in the link to download these types of files opens
  • Loading branch information
kylehickinson committed Oct 18, 2023
1 parent 9a5d726 commit 2cc24b1
Showing 1 changed file with 37 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import Growth
import SafariServices
import LocalAuthentication
import BraveShared
import UniformTypeIdentifiers

extension WKNavigationAction {
/// Allow local requests only if the request is privileged.
Expand Down Expand Up @@ -49,6 +50,11 @@ extension WKNavigationType: CustomDebugStringConvertible {
}
}

extension UTType {
static let textCalendar = UTType(mimeType: "text/calendar")! // Not the same as `calendarEvent`
static let mobileConfiguration = UTType(mimeType: "application/x-apple-aspen-config")!
}

// MARK: WKNavigationDelegate
extension BrowserViewController: WKNavigationDelegate {
public func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
Expand Down Expand Up @@ -195,18 +201,6 @@ extension BrowserViewController: WKNavigationDelegate {
return (.cancel, preferences)
}

// Handling calendar .ics files
if navigationAction.targetFrame?.isMainFrame == true, requestURL.pathExtension.lowercased() == "ics" {
// This is not ideal. It pushes a new view controller on top of the BVC
// and you have to dismiss it manually after you managed the calendar event.
// I do not see a workaround for it, Chrome iOS does the same thing.
let vc = SFSafariViewController(url: requestURL, configuration: .init())
vc.modalPresentationStyle = .formSheet
self.present(vc, animated: true)

return (.cancel, preferences)
}

// handles IPFS URL schemes
if requestURL.isIPFSScheme {
if navigationAction.targetFrame?.isMainFrame == true {
Expand Down Expand Up @@ -419,6 +413,24 @@ extension BrowserViewController: WKNavigationDelegate {

return (.cancel, preferences)
}

/// Handles a link by opening it in an SFSafariViewController and presenting it on the BVC.
///
/// This is unfortunately neccessary to handle certain downloads natively such as ics/calendar invites and
/// mobileconfiguration files.
///
/// The user unfortunately has to dismiss it manually after they have handled the file.
/// Chrome iOS does the same
private func handleLinkWithSafariViewController(_ url: URL, tab: Tab?) {
let vc = SFSafariViewController(url: url, configuration: .init())
vc.modalPresentationStyle = .formSheet
self.present(vc, animated: true)

// If the website opened this URL in a separate tab, remove the empty tab
if let tab = tab, tab.url == nil || tab.url?.absoluteString == "about:blank" {
tabManager.removeTab(tab)
}
}

@MainActor
public func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse) async -> WKNavigationResponsePolicy {
Expand Down Expand Up @@ -450,6 +462,19 @@ extension BrowserViewController: WKNavigationDelegate {
// download via the context menu.
let canShowInWebView = navigationResponse.canShowMIMEType && (webView != pendingDownloadWebView)
let forceDownload = webView == pendingDownloadWebView

let mimeTypesThatRequireSFSafariViewControllerHandling: [UTType] = [
.textCalendar,
.mobileConfiguration
]

// SFSafariViewController only supports http/https links
if navigationResponse.isForMainFrame, let url = responseURL, url.isWebPage(includeDataURIs: false),
let mimeType = response.mimeType.flatMap({ UTType(mimeType: $0) }),
mimeTypesThatRequireSFSafariViewControllerHandling.contains(mimeType) {
handleLinkWithSafariViewController(url, tab: tab)
return .cancel
}

// Check if this response should be handed off to Passbook.
if let passbookHelper = OpenPassBookHelper(request: request, response: response, canShowInWebView: canShowInWebView, forceDownload: forceDownload, browserViewController: self) {
Expand Down

0 comments on commit 2cc24b1

Please sign in to comment.