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

Commit

Permalink
Fix #8057: Add Download Delegate to handle PassKit blobs (#8588)
Browse files Browse the repository at this point in the history
Add download delegate to handle PassKit blobs
  • Loading branch information
Brandon-T committed Jan 2, 2024
1 parent d2f2338 commit 1c6d636
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Sources/Brave/Frontend/Browser/BrowserViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ public class BrowserViewController: UIViewController {
var downloadToast: DownloadToast? // A toast that is showing the combined download progress
var addToPlayListActivityItem: (enabled: Bool, item: PlaylistInfo?)? // A boolean to determine If AddToListActivity should be added
var openInPlaylistActivityItem: (enabled: Bool, item: PlaylistInfo?)? // A boolean to determine if OpenInPlaylistActivity should be shown
var shouldDownloadNavigationResponse: Bool = false
var pendingDownloads = [WKDownload: PendingDownload]()

var navigationToolbar: ToolbarProtocol {
return toolbar ?? topToolbar
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright 2021 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

import Foundation
import WebKit
import PassKit
import Shared

extension BrowserViewController: WKDownloadDelegate {

struct PendingDownload: Hashable, Equatable {
let fileURL: URL
let response: URLResponse
let suggestedFileName: String
}

public func download(_ download: WKDownload, decideDestinationUsing response: URLResponse, suggestedFilename: String) async -> URL? {
let temporaryDir = NSTemporaryDirectory()
let fileName = temporaryDir + "/" + suggestedFilename
let url = URL(fileURLWithPath: fileName)
pendingDownloads[download] = PendingDownload(fileURL: url, response: response, suggestedFileName: suggestedFilename)
return url
}

public func download(_ download: WKDownload, decidedPolicyForHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest) async -> WKDownload.RedirectPolicy {
return .allow
}

public func download(_ download: WKDownload, respondTo challenge: URLAuthenticationChallenge) async -> (URLSession.AuthChallengeDisposition, URLCredential?) {
return (.performDefaultHandling, nil)
}

@MainActor
public func downloadDidFinish(_ download: WKDownload) {
guard let downloadInfo = pendingDownloads[download] else {
return
}

pendingDownloads.removeValue(forKey: download)

let response = URLResponse(url: downloadInfo.fileURL,
mimeType: downloadInfo.response.mimeType,
expectedContentLength: Int(downloadInfo.response.expectedContentLength),
textEncodingName: downloadInfo.response.textEncodingName)

if let passbookHelper = OpenPassBookHelper(request: nil, response: response, canShowInWebView: false, forceDownload: false, browserViewController: self) {
passbookHelper.open()
}

Task {
try FileManager.default.removeItem(at: downloadInfo.fileURL)
}
}

@MainActor
public func download(_ download: WKDownload, didFailWithError error: Error, resumeData: Data?) {
// display an error
let alertController = UIAlertController(
title: Strings.unableToAddPassErrorTitle,
message: Strings.unableToAddPassErrorMessage,
preferredStyle: .alert)
alertController.addAction(
UIAlertAction(title: Strings.unableToAddPassErrorDismiss, style: .cancel) { (action) in
// Do nothing.
}
)
present(alertController, animated: true, completion: nil)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,10 @@ extension BrowserViewController: WKNavigationDelegate {
self.tabManager.selectedTab?.blockAllAlerts = false
}

if navigationAction.shouldPerformDownload {
self.shouldDownloadNavigationResponse = true
}

return (.allow, preferences)
}

Expand Down Expand Up @@ -493,6 +497,14 @@ extension BrowserViewController: WKNavigationDelegate {
}

// Check if this response should be handed off to Passbook.
if shouldDownloadNavigationResponse {
shouldDownloadNavigationResponse = false

if response.mimeType == MIMEType.passbook {
return .download
}
}

if let passbookHelper = OpenPassBookHelper(request: request, response: response, canShowInWebView: canShowInWebView, forceDownload: forceDownload, browserViewController: self) {
// Open our helper and cancel this response from the webview.
passbookHelper.open()
Expand Down Expand Up @@ -529,11 +541,23 @@ extension BrowserViewController: WKNavigationDelegate {

tab.mimeType = response.mimeType
}

if canShowInWebView {
return .allow
}

// If none of our helpers are responsible for handling this response,
// just let the webview handle it as normal.
return .allow
}

public func webView(_ webView: WKWebView, navigationAction: WKNavigationAction, didBecome download: WKDownload) {
Logger.module.error("ERROR: Should Never download NavigationAction since we never return .download from decidePolicyForAction.")
}

public func webView(_ webView: WKWebView, navigationResponse: WKNavigationResponse, didBecome download: WKDownload) {
download.delegate = self
}

nonisolated public func webView(_ webView: WKWebView, respondTo challenge: URLAuthenticationChallenge) async -> (URLSession.AuthChallengeDisposition, URLCredential?) {

Expand Down
28 changes: 28 additions & 0 deletions Sources/Brave/Frontend/Browser/TabManagerNavDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ class TabManagerNavDelegate: NSObject, WKNavigationDelegate {
res = policy
}

if policy == .download {
res = policy
}

pref = preferences
}
}
Expand All @@ -127,6 +131,10 @@ class TabManagerNavDelegate: NSObject, WKNavigationDelegate {
if policy == .cancel {
res = policy
}

if policy == .download {
res = policy
}
}
}

Expand All @@ -137,4 +145,24 @@ class TabManagerNavDelegate: NSObject, WKNavigationDelegate {

return res
}

@MainActor
public func webView(_ webView: WKWebView, navigationAction: WKNavigationAction, didBecome download: WKDownload) {
for delegate in delegates {
delegate.webView?(webView, navigationAction: navigationAction, didBecome: download)
if download.delegate != nil {
return
}
}
}

@MainActor
public func webView(_ webView: WKWebView, navigationResponse: WKNavigationResponse, didBecome download: WKDownload) {
for delegate in delegates {
delegate.webView?(webView, navigationResponse: navigationResponse, didBecome: download)
if download.delegate != nil {
return
}
}
}
}

0 comments on commit 1c6d636

Please sign in to comment.