@@ -66,17 +66,9 @@ extension BrowserViewController: WKNavigationDelegate {
66
66
67
67
// check if web view is loading a different origin than the one currently loaded
68
68
if let selectedTab = tabManager. selectedTab,
69
- selectedTab. url? . origin != webView. url? . origin {
70
- if let url = webView. url {
71
- if !InternalURL. isValid ( url: url) {
72
- // reset secure content state to unknown until page can be evaluated
73
- selectedTab. sslPinningError = nil
74
- selectedTab. sslPinningTrust = nil
75
- selectedTab. secureContentState = . unknown
76
- updateToolbarSecureContentState ( . unknown)
77
- }
78
- }
79
-
69
+ selectedTab. url? . origin != webView. url? . origin
70
+ {
71
+
80
72
// new site has a different origin, hide wallet icon.
81
73
tabManager. selectedTab? . isWalletIconVisible = false
82
74
// new site, reset connected addresses
@@ -606,16 +598,28 @@ extension BrowserViewController: WKNavigationDelegate {
606
598
download. delegate = self
607
599
}
608
600
609
- nonisolated public func webView( _ webView: WKWebView , respondTo challenge: URLAuthenticationChallenge ) async -> ( URLSession . AuthChallengeDisposition , URLCredential ? ) {
601
+
602
+ @MainActor
603
+
604
+ public func webView(
605
+ _ webView: WKWebView ,
606
+ respondTo challenge: URLAuthenticationChallenge
607
+ ) async -> ( URLSession . AuthChallengeDisposition , URLCredential ? ) {
610
608
611
609
// If this is a certificate challenge, see if the certificate has previously been
612
610
// accepted by the user.
613
611
let host = challenge. protectionSpace. host
614
612
let origin = " \( host) : \( challenge. protectionSpace. port) "
615
613
if challenge. protectionSpace. authenticationMethod == NSURLAuthenticationMethodServerTrust,
616
- let trust = challenge. protectionSpace. serverTrust,
617
- let cert = ( SecTrustCopyCertificateChain ( trust) as? [ SecCertificate ] ) ? . first, profile. certStore. containsCertificate ( cert, forOrigin: origin) {
618
- return ( . useCredential, URLCredential ( trust: trust) )
614
+ let trust = challenge. protectionSpace. serverTrust
615
+ {
616
+ let cert = await Task < SecCertificate ? , Never > . detached {
617
+ return ( SecTrustCopyCertificateChain ( trust) as? [ SecCertificate ] ) ? . first
618
+ } . value
619
+
620
+ if let cert = cert, profile. certStore. containsCertificate ( cert, forOrigin: origin) {
621
+ return ( . useCredential, URLCredential ( trust: trust) )
622
+ }
619
623
}
620
624
621
625
// Certificate Pinning
@@ -636,36 +640,35 @@ extension BrowserViewController: WKNavigationDelegate {
636
640
// Let the system handle it and we'll show an error if the system cannot validate it
637
641
if result == Int32 . min {
638
642
// Cert is POTENTIALLY invalid and cannot be pinned
639
-
640
- await MainActor . run {
641
- // Handle the potential error later in `didFailProvisionalNavigation`
642
- self . tab ( for: webView) ? . sslPinningTrust = serverTrust
643
- }
644
-
643
+
645
644
// Let WebKit handle the request and validate the cert
646
- // This is the same as calling `BraveCertificateUtils.evaluateTrust`
645
+ // This is the same as calling `BraveCertificateUtils.evaluateTrust` but with more error info provided by WebKit
647
646
return ( . performDefaultHandling, nil )
648
647
}
649
648
650
649
// Cert is invalid and cannot be pinned
651
650
Logger . module. error ( " CERTIFICATE_INVALID " )
652
651
let errorCode = CFNetworkErrors . braveCertificatePinningFailed. rawValue
653
-
654
- let underlyingError = NSError ( domain: kCFErrorDomainCFNetwork as String ,
655
- code: Int ( errorCode) ,
656
- userInfo: [ " _kCFStreamErrorCodeKey " : Int ( errorCode) ] )
657
-
658
- let error = await NSError ( domain: kCFErrorDomainCFNetwork as String ,
659
- code: Int ( errorCode) ,
660
- userInfo: [ NSURLErrorFailingURLErrorKey: webView. url as Any ,
661
- " NSErrorPeerCertificateChainKey " : certificateChain,
662
- NSUnderlyingErrorKey: underlyingError] )
663
-
664
- await MainActor . run {
665
- // Handle the error later in `didFailProvisionalNavigation`
666
- self . tab ( for: webView) ? . sslPinningError = error
667
- }
668
-
652
+
653
+ let underlyingError = NSError (
654
+ domain: kCFErrorDomainCFNetwork as String ,
655
+ code: Int ( errorCode) ,
656
+ userInfo: [ " _kCFStreamErrorCodeKey " : Int ( errorCode) ]
657
+ )
658
+
659
+ let error = NSError (
660
+ domain: kCFErrorDomainCFNetwork as String ,
661
+ code: Int ( errorCode) ,
662
+ userInfo: [
663
+ NSURLErrorFailingURLErrorKey: webView. url as Any ,
664
+ " NSErrorPeerCertificateChainKey " : certificateChain,
665
+ NSUnderlyingErrorKey: underlyingError,
666
+ ]
667
+ )
668
+
669
+ // Handle the error later in `didFailProvisionalNavigation`
670
+ self . tab ( for: webView) ? . sslPinningError = error
671
+
669
672
return ( . cancelAuthenticationChallenge, nil )
670
673
}
671
674
}
@@ -674,35 +677,38 @@ extension BrowserViewController: WKNavigationDelegate {
674
677
let protectionSpace = challenge. protectionSpace
675
678
let credential = challenge. proposedCredential
676
679
let previousFailureCount = challenge. previousFailureCount
677
- return await Task { @MainActor in
678
- guard protectionSpace. authenticationMethod == NSURLAuthenticationMethodHTTPBasic ||
679
- protectionSpace. authenticationMethod == NSURLAuthenticationMethodHTTPDigest ||
680
- protectionSpace. authenticationMethod == NSURLAuthenticationMethodNTLM,
681
- let tab = tab ( for: webView)
682
- else {
683
- return ( . performDefaultHandling, nil )
684
- }
685
-
686
- // The challenge may come from a background tab, so ensure it's the one visible.
687
- tabManager. selectTab ( tab)
688
-
689
- do {
690
- let credentials = try await Authenticator . handleAuthRequest (
691
- self ,
692
- credential: credential,
693
- protectionSpace: protectionSpace,
694
- previousFailureCount: previousFailureCount
680
+
681
+ guard
682
+ protectionSpace. authenticationMethod == NSURLAuthenticationMethodHTTPBasic
683
+ || protectionSpace. authenticationMethod == NSURLAuthenticationMethodHTTPDigest
684
+ || protectionSpace. authenticationMethod == NSURLAuthenticationMethodNTLM,
685
+ let tab = tab ( for: webView)
686
+ else {
687
+ return ( . performDefaultHandling, nil )
688
+ }
689
+
690
+ // The challenge may come from a background tab, so ensure it's the one visible.
691
+ tabManager. selectTab ( tab)
692
+
693
+ do {
694
+ let credentials = try await Authenticator . handleAuthRequest (
695
+ self ,
696
+ credential: credential,
697
+ protectionSpace: protectionSpace,
698
+ previousFailureCount: previousFailureCount
699
+ )
700
+
701
+ if BasicAuthCredentialsManager . validDomains. contains ( host) {
702
+ BasicAuthCredentialsManager . setCredential (
703
+ origin: origin,
704
+ credential: credentials. credentials
695
705
)
696
-
697
- if BasicAuthCredentialsManager . validDomains. contains ( host) {
698
- BasicAuthCredentialsManager . setCredential ( origin: origin, credential: credentials. credentials)
699
- }
700
-
701
- return ( . useCredential, credentials. credentials)
702
- } catch {
703
- return ( . rejectProtectionSpace, nil )
704
706
}
705
- } . value
707
+
708
+ return ( . useCredential, credentials. credentials)
709
+ } catch {
710
+ return ( . rejectProtectionSpace, nil )
711
+ }
706
712
}
707
713
708
714
public func webView( _ webView: WKWebView , didCommit navigation: WKNavigation ! ) {
@@ -817,17 +823,7 @@ extension BrowserViewController: WKNavigationDelegate {
817
823
/// Invoked when an error occurs while starting to load data for the main frame.
818
824
public func webView( _ webView: WKWebView , didFailProvisionalNavigation navigation: WKNavigation ! , withError error: Error ) {
819
825
guard let tab = tab ( for: webView) else { return }
820
-
821
- // WebKit does not update certs on cancellation of a frame load
822
- // So manually trigger the notification with the current cert
823
- // Also, when Chromium cert validation passes, BUT Apple cert validation fails, the request is cancelled automatically by WebKit
824
- // In such a case, the webView.serverTrust is `nil`. The only time we have a valid trust is when we received the challenge
825
- // so we need to update the URL-Bar to show that serverTrust when WebKit's is nil.
826
- observeValue ( forKeyPath: KVOConstants . serverTrust. keyPath,
827
- of: webView,
828
- change: [ . newKey: webView. serverTrust ?? tab. sslPinningTrust as Any , . kindKey: 1 ] ,
829
- context: nil )
830
-
826
+
831
827
// Ignore the "Frame load interrupted" error that is triggered when we cancel a request
832
828
// to open an external application and hand it over to UIApplication.openURL(). The result
833
829
// will be that we switch to the external app, for example the app store, while keeping the
@@ -858,20 +854,10 @@ extension BrowserViewController: WKNavigationDelegate {
858
854
}
859
855
860
856
if let url = error. userInfo [ NSURLErrorFailingURLErrorKey] as? URL {
861
-
862
- // The certificate came from the WebKit SSL Handshake validation and the cert is untrusted
863
- if webView. serverTrust == nil , let serverTrust = tab. sslPinningTrust, error. userInfo [ " NSErrorPeerCertificateChainKey " ] == nil {
864
- // Build a cert chain error to display in the cert viewer in such cases, as we aren't given one by WebKit
865
- var userInfo = error. userInfo
866
- userInfo [ " NSErrorPeerCertificateChainKey " ] = SecTrustCopyCertificateChain ( serverTrust) as? [ SecCertificate ] ?? [ ]
867
- userInfo [ " NSErrorPeerUntrustedByApple " ] = true
868
- error = NSError ( domain: error. domain, code: error. code, userInfo: userInfo)
857
+
858
+ if tab == self . tabManager. selectedTab {
859
+ self . topToolbar. hideProgressBar ( )
869
860
}
870
-
871
- ErrorPageHelper ( certStore: profile. certStore) . loadPage ( error, forUrl: url, inWebView: webView)
872
- // Submitting same errornous URL using toolbar will cause progress bar get stuck
873
- // Reseting the progress bar in case there is an error is necessary
874
- topToolbar. hideProgressBar ( )
875
861
876
862
// If the local web server isn't working for some reason (Brave cellular data is
877
863
// disabled in settings, for example), we'll fail to load the session restore URL.
@@ -912,55 +898,48 @@ extension BrowserViewController {
912
898
private func handleExternalURL(
913
899
_ url: URL ,
914
900
tab: Tab ? ,
915
- navigationAction: WKNavigationAction ) async -> Bool {
916
- // Do not open external links for child tabs automatically
917
- // The user must tap on the link to open it.
918
- if tab? . parent != nil && navigationAction. navigationType != . linkActivated {
919
- return false
920
- }
921
-
922
- // Check if the current url of the caller has changed
923
- if let domain = tab? . url? . baseDomain,
924
- domain != tab? . externalAppURLDomain {
925
- tab? . externalAppAlertCounter = 0
926
- tab? . isExternalAppAlertSuppressed = false
927
- }
928
-
929
- tab? . externalAppURLDomain = tab? . url? . baseDomain
930
-
931
- // Do not try to present over existing warning
932
- if tab? . isExternalAppAlertPresented == true || tab? . isExternalAppAlertSuppressed == true {
933
- return false
934
- }
935
-
936
- // External dialog should not be shown for non-active tabs #6687 - #7835
937
- let isVisibleTab = tab? . isTabVisible ( ) == true
938
-
939
- // Check user trying to open on NTP like external link browsing
940
- var isAboutHome = false
941
- if let url = tab? . url {
942
- isAboutHome = InternalURL ( url) ? . isAboutHomeURL == true
943
- }
944
-
945
- // Finally check non-active tab
946
- let isNonActiveTab = isAboutHome ? false : tab? . url? . host != topToolbar. currentURL? . host
947
-
948
- if !isVisibleTab || isNonActiveTab {
949
- return false
950
- }
951
-
952
- var alertTitle = Strings . openExternalAppURLGenericTitle
953
-
954
- if let displayHost = tab? . url? . withoutWWW. host {
955
- alertTitle = String ( format: Strings . openExternalAppURLTitle, displayHost)
956
- }
957
-
958
- // Handling condition when Tab is empty when handling an external URL we should remove the tab once the user decides
959
- let removeTabIfEmpty = { [ weak self] in
960
- if let tab = tab, tab. url == nil {
961
- self ? . tabManager. removeTab ( tab)
962
- }
901
+ navigationAction: WKNavigationAction
902
+ ) async -> Bool {
903
+ // Do not open external links for child tabs automatically
904
+ // The user must tap on the link to open it.
905
+ if tab? . parent != nil && navigationAction. navigationType != . linkActivated {
906
+ return false
907
+ }
908
+
909
+ // Check if the current url of the caller has changed
910
+ if let domain = tab? . url? . baseDomain,
911
+ domain != tab? . externalAppURLDomain
912
+ {
913
+ tab? . externalAppAlertCounter = 0
914
+ tab? . isExternalAppAlertSuppressed = false
915
+ }
916
+
917
+ tab? . externalAppURLDomain = tab? . url? . baseDomain
918
+
919
+ // Do not try to present over existing warning
920
+ if tab? . isExternalAppAlertPresented == true || tab? . isExternalAppAlertSuppressed == true {
921
+ return false
922
+ }
923
+
924
+ // External dialog should not be shown for non-active tabs #6687 - #7835
925
+ let isVisibleTab = tab? . isTabVisible ( ) == true
926
+
927
+ if !isVisibleTab {
928
+ return false
929
+ }
930
+
931
+ var alertTitle = Strings . openExternalAppURLGenericTitle
932
+
933
+ if let displayHost = tab? . url? . withoutWWW. host {
934
+ alertTitle = String ( format: Strings . openExternalAppURLTitle, displayHost)
935
+ }
936
+
937
+ // Handling condition when Tab is empty when handling an external URL we should remove the tab once the user decides
938
+ let removeTabIfEmpty = { [ weak self] in
939
+ if let tab = tab, tab. url == nil {
940
+ self ? . tabManager. removeTab ( tab)
963
941
}
942
+ }
964
943
965
944
// Show the external sceheme invoke alert
966
945
@MainActor
0 commit comments