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

Commit f41582f

Browse files
authored
Fix #8768: Add Logging to Track Secure Content State (#8769)
1 parent e57c25e commit f41582f

13 files changed

+225
-92
lines changed

App/iOS/Delegates/AppDelegate.swift

+4
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
107107
}
108108

109109
SystemUtils.onFirstRun()
110+
111+
// Clean Logger for Secure content state
112+
DebugLogger.cleanLogger(for: .secureState)
113+
110114
return true
111115
}
112116

Sources/Brave/Frontend/Browser/BrowserViewController/BVC+ShareActivity.swift

+3-1
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,9 @@ extension BrowserViewController {
268268
}
269269

270270
// Display Certificate Activity
271-
if let secureState = tabManager.selectedTab?.secureContentState, secureState != .missingSSL && secureState != .unknown {
271+
if let selectedTab = tabManager.selectedTab, selectedTab.secureContentState != .missingSSL && selectedTab.secureContentState != .unknown {
272+
logSecureContentState(tab: selectedTab, details: "Display Certificate Activity Settings")
273+
272274
activities.append(
273275
BasicMenuActivity(
274276
title: Strings.displayCertificate,

Sources/Brave/Frontend/Browser/BrowserViewController/BVC+WKNavigationDelegate.swift

+6
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ extension BrowserViewController: WKNavigationDelegate {
7373
selectedTab.sslPinningError = nil
7474
selectedTab.sslPinningTrust = nil
7575
selectedTab.secureContentState = .unknown
76+
logSecureContentState(tab: selectedTab, details: "DidStartProvisionalNavigation - Reset secure content state to unknown until page can be evaluated")
77+
7678
updateToolbarSecureContentState(.unknown)
7779
}
7880
}
@@ -715,6 +717,8 @@ extension BrowserViewController: WKNavigationDelegate {
715717
// However, WebKit does NOT trigger the `serverTrust` observer when the URL changes, but the trust has not.
716718
// WebKit also does NOT trigger the `serverTrust` observer when the page is actually insecure (non-https).
717719
// So manually trigger it with the current trust.
720+
logSecureContentState(tab: tab, details: "ObserveValue trigger in didCommit")
721+
718722
observeValue(forKeyPath: KVOConstants.serverTrust.keyPath,
719723
of: webView,
720724
change: [.newKey: webView.serverTrust as Any, .kindKey: 1],
@@ -823,6 +827,8 @@ extension BrowserViewController: WKNavigationDelegate {
823827
// Also, when Chromium cert validation passes, BUT Apple cert validation fails, the request is cancelled automatically by WebKit
824828
// In such a case, the webView.serverTrust is `nil`. The only time we have a valid trust is when we received the challenge
825829
// so we need to update the URL-Bar to show that serverTrust when WebKit's is nil.
830+
logSecureContentState(tab: tab, details: "ObserveValue trigger in didFailProvisionalNavigation")
831+
826832
observeValue(forKeyPath: KVOConstants.serverTrust.keyPath,
827833
of: webView,
828834
change: [.newKey: webView.serverTrust ?? tab.sslPinningTrust as Any, .kindKey: 1],

Sources/Brave/Frontend/Browser/BrowserViewController/BrowserViewController.swift

+48-1
Original file line numberDiff line numberDiff line change
@@ -1834,6 +1834,7 @@ public class BrowserViewController: UIViewController {
18341834
}
18351835

18361836
tab.secureContentState = .mixedContent
1837+
logSecureContentState(tab: tab, path: path)
18371838
}
18381839

18391840
if let url = tab.webView?.url,
@@ -1844,18 +1845,22 @@ public class BrowserViewController: UIViewController {
18441845
if ErrorPageHelper.certificateError(for: url) != 0 {
18451846
// Cert validation takes precedence over all other errors
18461847
tab.secureContentState = .invalidCert
1848+
logSecureContentState(tab: tab, path: path, details: "Cert validation takes precedence over all other errors")
18471849
} else if NetworkErrorPageHandler.isNetworkError(errorCode: ErrorPageHelper.errorCode(for: url)) {
18481850
// Network error takes precedence over missing cert
18491851
// Because we cannot determine if a cert is missing yet, if we cannot connect to the server
18501852
// Our network interstitial page shows
18511853
tab.secureContentState = .localhost
1854+
logSecureContentState(tab: tab, path: path, details: "Network error takes precedence over missing cert")
18521855
} else {
18531856
// Since it's not a cert error explicitly, and it's not a network error, and the cert is missing (no serverTrust),
18541857
// then we display .missingSSL
18551858
tab.secureContentState = .missingSSL
1859+
logSecureContentState(tab: tab, path: path, details: "Certificate is missing (no serverTrust)")
18561860
}
18571861
} else if url.isReaderModeURL || InternalURL.isValid(url: url) {
18581862
tab.secureContentState = .localhost
1863+
logSecureContentState(tab: tab, path: path, details: "Reader Mode or Internal URL")
18591864
}
18601865
}
18611866

@@ -1868,14 +1873,17 @@ public class BrowserViewController: UIViewController {
18681873
}
18691874

18701875
tab.secureContentState = .unknown
1871-
1876+
logSecureContentState(tab: tab, path: path)
1877+
18721878
guard let serverTrust = tab.webView?.serverTrust else {
18731879
if let url = tab.webView?.url ?? tab.url {
18741880
if InternalURL.isValid(url: url),
18751881
let internalUrl = InternalURL(url),
18761882
(internalUrl.isAboutURL || internalUrl.isAboutHomeURL) {
18771883

18781884
tab.secureContentState = .localhost
1885+
logSecureContentState(tab: tab, path: path, details: "Internal URL aboutURL or is aboutHomeURL")
1886+
18791887
if tabManager.selectedTab === tab {
18801888
updateToolbarSecureContentState(.localhost)
18811889
}
@@ -1889,15 +1897,20 @@ public class BrowserViewController: UIViewController {
18891897
if ErrorPageHelper.certificateError(for: url) != 0 {
18901898
// Cert validation takes precedence over all other errors
18911899
tab.secureContentState = .invalidCert
1900+
1901+
logSecureContentState(tab: tab, path: path, details: "Cert validation takes precedence over all other errors")
18921902
} else if NetworkErrorPageHandler.isNetworkError(errorCode: ErrorPageHelper.errorCode(for: url)) {
18931903
// Network error takes precedence over missing cert
18941904
// Because we cannot determine if a cert is missing yet, if we cannot connect to the server
18951905
// Our network interstitial page shows
18961906
tab.secureContentState = .localhost
1907+
1908+
logSecureContentState(tab: tab, path: path, details: "Network error takes precedence over missing cert")
18971909
} else {
18981910
// Since it's not a cert error explicitly, and it's not a network error, and the cert is missing (no serverTrust),
18991911
// then we display .missingSSL
19001912
tab.secureContentState = .missingSSL
1913+
logSecureContentState(tab: tab, path: path, details: "Certificate is missing (no serverTrust)")
19011914
}
19021915

19031916
if tabManager.selectedTab === tab {
@@ -1908,6 +1921,8 @@ public class BrowserViewController: UIViewController {
19081921

19091922
if url.isReaderModeURL || InternalURL.isValid(url: url) {
19101923
tab.secureContentState = .localhost
1924+
logSecureContentState(tab: tab, path: path, details: "Reader Mode or Internal URL")
1925+
19111926
if tabManager.selectedTab === tab {
19121927
updateToolbarSecureContentState(.localhost)
19131928
}
@@ -1916,9 +1931,13 @@ public class BrowserViewController: UIViewController {
19161931

19171932
// All our checks failed, we show the page as insecure
19181933
tab.secureContentState = .missingSSL
1934+
1935+
logSecureContentState(tab: tab, path: path, details: "All our checks failed, we show the page as insecure")
19191936
} else {
19201937
// When there is no URL, it's likely a new tab.
19211938
tab.secureContentState = .localhost
1939+
1940+
logSecureContentState(tab: tab, path: path, details: "When there is no URL, it's likely a new tab")
19221941
}
19231942

19241943
if tabManager.selectedTab === tab {
@@ -1930,6 +1949,8 @@ public class BrowserViewController: UIViewController {
19301949
guard let scheme = tab.webView?.url?.scheme,
19311950
let host = tab.webView?.url?.host else {
19321951
tab.secureContentState = .unknown
1952+
logSecureContentState(tab: tab, path: path, details: "No webview URL host scheme)")
1953+
19331954
self.updateURLBar()
19341955
return
19351956
}
@@ -1950,16 +1971,24 @@ public class BrowserViewController: UIViewController {
19501971
// Cert is valid!
19511972
if result == 0 {
19521973
tab.secureContentState = .secure
1974+
1975+
logSecureContentState(tab: tab, path: path, details: "Cert is valid!")
19531976
} else if result == Int32.min {
19541977
// Cert is valid but should be validated by the system
19551978
// Let the system handle it and we'll show an error if the system cannot validate it
19561979
try await BraveCertificateUtils.evaluateTrust(serverTrust, for: host)
19571980
tab.secureContentState = .secure
1981+
1982+
logSecureContentState(tab: tab, path: path, details: "Cert is valid but should be validated by the system")
19581983
} else {
19591984
tab.secureContentState = .invalidCert
1985+
1986+
logSecureContentState(tab: tab, path: path, details: "Invalid Cert")
19601987
}
19611988
} catch {
19621989
tab.secureContentState = .invalidCert
1990+
1991+
logSecureContentState(tab: tab, path: path, details: "Verify Trust Error")
19631992
}
19641993

19651994
self.updateURLBar()
@@ -1971,6 +2000,24 @@ public class BrowserViewController: UIViewController {
19712000
}
19722001
}
19732002

2003+
func logSecureContentState(tab: Tab, path: KVOConstants? = nil, details: String? = nil) {
2004+
var text = """
2005+
Tab URL: \(tab.url?.absoluteString ?? "Empty Tab URL")
2006+
Tab VebView URL: \(tab.webView?.url?.absoluteString ?? "Empty Webview URL")
2007+
Secure State: \(tab.secureContentState.rawValue)
2008+
"""
2009+
2010+
if let keyPath = path?.keyPath {
2011+
text.append("\n Value Observed: \(keyPath)\n")
2012+
}
2013+
2014+
if let extraDetails = details {
2015+
text.append("\n Extra Details: \(extraDetails)\n")
2016+
}
2017+
2018+
DebugLogger.log(for: .secureState, text: text)
2019+
}
2020+
19742021
func updateForwardStatusIfNeeded(webView: WKWebView) {
19752022
if let forwardListItem = webView.backForwardList.forwardList.first, forwardListItem.url.isReaderModeURL {
19762023
navigationToolbar.updateForwardStatus(false)

Sources/Brave/Frontend/Browser/Tab.swift

+8-8
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,14 @@ protocol URLChangeDelegate {
5757
func tab(_ tab: Tab, urlDidChangeTo url: URL)
5858
}
5959

60-
enum TabSecureContentState {
61-
case unknown
62-
case localhost
63-
case secure
64-
case invalidCert
65-
case missingSSL
66-
case mixedContent
67-
60+
enum TabSecureContentState: String {
61+
case unknown = "Unknown"
62+
case localhost = "Localhost"
63+
case secure = "Secure"
64+
case invalidCert = "InvalidCertificate"
65+
case missingSSL = "SSL Certificate Missing"
66+
case mixedContent = "Mixed Content"
67+
6868
var shouldDisplayWarning: Bool {
6969
switch self {
7070
case .unknown, .invalidCert, .missingSSL, .mixedContent:

Sources/Brave/Frontend/Settings/SettingsViewController.swift

+6-1
Original file line numberDiff line numberDiff line change
@@ -809,10 +809,15 @@ class SettingsViewController: TableViewController {
809809
let vc = AdblockDebugMenuTableViewController(style: .grouped)
810810
self.navigationController?.pushViewController(vc, animated: true)
811811
}, accessory: .disclosureIndicator, cellClass: MultilineValue1Cell.self),
812+
Row(
813+
text: "Secure Content State Debug",
814+
selection: { [unowned self] in
815+
self.navigationController?.pushViewController(DebugLogViewController(type: .secureState), animated: true)
816+
}, accessory: .disclosureIndicator, cellClass: MultilineValue1Cell.self),
812817
Row(
813818
text: "View URP Logs",
814819
selection: { [unowned self] in
815-
self.navigationController?.pushViewController(UrpLogsViewController(), animated: true)
820+
self.navigationController?.pushViewController(DebugLogViewController(type: .urp), animated: true)
816821
}, accessory: .disclosureIndicator, cellClass: MultilineValue1Cell.self),
817822
Row(text: "URP Code: \(UserReferralProgram.getReferralCode() ?? "--")"),
818823
Row(

Sources/BraveShared/DebugLogger.swift

+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// Copyright 2024 The Brave Authors. All rights reserved.
2+
// This Source Code Form is subject to the terms of the Mozilla Public
3+
// License, v. 2.0. If a copy of the MPL was not distributed with this
4+
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
5+
6+
import UIKit
7+
8+
public enum LoggerType {
9+
case urp, secureState
10+
11+
var prefsKey: String {
12+
switch self {
13+
case .urp:
14+
return "urpLogs"
15+
case .secureState:
16+
return "secureStateLogs"
17+
}
18+
}
19+
}
20+
21+
public struct DebugLogger {
22+
public static func log(for type: LoggerType, text: String) {
23+
var logs = UserDefaults.standard.string(forKey: type.prefsKey) ?? ""
24+
25+
let date = Date()
26+
let calendar = Calendar.current
27+
let components = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: date)
28+
29+
guard let year = components.year, let month = components.month, let day = components.day, let hour = components.hour, let minute = components.minute else {
30+
return
31+
}
32+
let time = "\(year)-\(month)-\(day) \(hour):\(minute)"
33+
34+
switch type {
35+
case .secureState:
36+
logs.append("------------------------------------\n\n")
37+
logs.append(" [\(time)]\n\n \(text)\n")
38+
case .urp:
39+
logs.append("[\(time)] \(text)\n")
40+
}
41+
42+
UserDefaults.standard.set(logs, forKey: type.prefsKey)
43+
}
44+
45+
public static func cleanLogger(for type: LoggerType) {
46+
UserDefaults.standard.removeObject(forKey: type.prefsKey)
47+
}
48+
}
49+
50+
public class DebugLogViewController: UIViewController {
51+
var loggerType: LoggerType
52+
53+
public init(type: LoggerType) {
54+
loggerType = type
55+
56+
super.init(nibName: nil, bundle: nil)
57+
}
58+
59+
required init?(coder: NSCoder) {
60+
fatalError("init(coder:) has not been implemented")
61+
}
62+
63+
public override func viewDidLoad() {
64+
super.viewDidLoad()
65+
66+
switch loggerType {
67+
case .urp:
68+
title = "URP Logs"
69+
case .secureState:
70+
title = "Secure Content State"
71+
}
72+
73+
let rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(shareButtonTapped))
74+
navigationItem.rightBarButtonItem = rightBarButtonItem
75+
76+
let textView = UITextView()
77+
textView.translatesAutoresizingMaskIntoConstraints = false
78+
textView.isEditable = false
79+
80+
view.addSubview(textView)
81+
82+
NSLayoutConstraint.activate([
83+
textView.topAnchor.constraint(
84+
equalTo: view.topAnchor, constant: 8),
85+
textView.leadingAnchor.constraint(
86+
equalTo: view.leadingAnchor, constant: 8),
87+
textView.trailingAnchor.constraint(
88+
equalTo: view.trailingAnchor, constant: -8),
89+
textView.bottomAnchor.constraint(
90+
equalTo: view.bottomAnchor, constant: -8)
91+
])
92+
93+
guard let logs = UserDefaults.standard.string(forKey: loggerType.prefsKey) else { return }
94+
let title = "Secure Content Logs\n\n"
95+
96+
textView.text = title + logs
97+
}
98+
99+
@objc func shareButtonTapped() {
100+
guard let logs = UserDefaults.standard.string(forKey: loggerType.prefsKey) else { return }
101+
102+
// Create an activity view controller with the text to share
103+
let activityViewController = UIActivityViewController(activityItems: [logs], applicationActivities: nil)
104+
105+
// Present the activity view controller
106+
if let popoverController = activityViewController.popoverPresentationController {
107+
popoverController.barButtonItem = navigationItem.rightBarButtonItem
108+
}
109+
present(activityViewController, animated: true, completion: nil)
110+
}
111+
}

Sources/Growth/DAU.swift

+6-5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import Shared
55
import BraveCore
66
import os.log
77
import Preferences
8+
import BraveShared
89

910
public class DAU {
1011

@@ -92,7 +93,7 @@ public class DAU {
9293
@objc private func sendPingToServerInternal() {
9394
guard let paramsAndPrefs = paramsAndPrefsSetup(for: Date()) else {
9495
Logger.module.debug("dau, no changes detected, no server ping")
95-
UrpLog.log("dau, no changes detected, no server ping")
96+
DebugLogger.log(for: .urp, text: "dau, no changes detected, no server ping")
9697
return
9798
}
9899

@@ -112,8 +113,8 @@ public class DAU {
112113
}
113114

114115
Logger.module.debug("send ping to server, url: \(pingRequestUrl)")
115-
UrpLog.log("send ping to server, url: \(pingRequestUrl)")
116-
116+
DebugLogger.log(for: .urp, text: "send ping to server, url: \(pingRequestUrl)")
117+
117118
var request = URLRequest(url: pingRequestUrl)
118119
for (key, value) in paramsAndPrefs.headers {
119120
request.setValue(value, forHTTPHeaderField: key)
@@ -126,7 +127,7 @@ public class DAU {
126127

127128
if let e = error {
128129
Logger.module.error("status update error: \(e.localizedDescription)")
129-
UrpLog.log("status update error: \(e)")
130+
DebugLogger.log(for: .urp, text: "status update error: \(e)")
130131
return
131132
}
132133

@@ -212,7 +213,7 @@ public class DAU {
212213

213214
if let referralCode = UserReferralProgram.getReferralCode() {
214215
params.append(URLQueryItem(name: "ref", value: referralCode))
215-
UrpLog.log("DAU ping with added ref, params: \(params)")
216+
DebugLogger.log(for: .urp, text: "DAU ping with added ref, params: \(params)")
216217
}
217218

218219
let lastPingTimestamp = [Int((date).timeIntervalSince1970)]

0 commit comments

Comments
 (0)