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

Fix #8173: Update URL bar design & display origin-only URLs #8417

Merged
merged 22 commits into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
132cd14
Make URL origin-only/leading truncated until edited
kylehickinson Nov 10, 2022
e581c09
Move rewards/shields buttons, remove lock, location shadow + height bump
kylehickinson Nov 7, 2023
cca104c
Center url properly and re-add leading fade, adjust fonts + icons sizes
kylehickinson Nov 8, 2023
5367bf0
Move progress bar into location view, fixup spacing/icon sizes
kylehickinson Nov 8, 2023
0116a7f
Add share button to landscape, replace forward in portrait when needed
kylehickinson Nov 8, 2023
2dd95de
Allow reader mode alongside playlist/wallet now thats a leading button
kylehickinson Nov 8, 2023
b550099
Add new tab button to landscape iPhone toolbar
kylehickinson Nov 8, 2023
1c256a0
Add new insecure states, long urls w/o leading item now use empty space
kylehickinson Nov 9, 2023
6007857
Use icon instead of text color for cert errors
kylehickinson Nov 9, 2023
8cf0784
Add second shadow to match Figma, fix clipping fade colors
kylehickinson Nov 13, 2023
e622477
Fix sharing button being enabled on error pages
kylehickinson Nov 13, 2023
bf23e1a
Add cert viewer to menu/share sheet, fix menu items on error pages
kylehickinson Nov 13, 2023
bfaa86f
Better spacing/uniformity for shields/rewards/bookmarks buttons
kylehickinson Nov 13, 2023
37d23a3
Add reader mode to menu when its occluded by an insecure page warning
kylehickinson Nov 13, 2023
fe8e8ec
Add popover when tapping insecure connection state warning
kylehickinson Nov 13, 2023
b1a17f2
Show missing SSL warning for non-cert related error pages
kylehickinson Nov 14, 2023
d35ca10
Clip RTL urls correctly and update url formatter to support RTL as well
kylehickinson Nov 14, 2023
4b5ee24
Cleanup
kylehickinson Nov 14, 2023
cd9f778
Fix education popup border
kylehickinson Nov 15, 2023
fc78f7e
Remove unsupported protocol case, show unknown on origin change/nav s…
kylehickinson Nov 16, 2023
63e3c1a
Dont use unknown secure content state for internal urls/reader mode
kylehickinson Nov 16, 2023
550a195
Check for origin mismatch before displaying mixed content warning
kylehickinson Nov 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 130 additions & 20 deletions Sources/Brave/Frontend/Browser/BrowserViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,7 @@ public class BrowserViewController: UIViewController {
updateTabsBarVisibility()
}

private func updateToolbarSecureContentState(_ secureContentState: TabSecureContentState) {
func updateToolbarSecureContentState(_ secureContentState: TabSecureContentState) {
topToolbar.secureContentState = secureContentState
collapsedURLBarView.secureContentState = secureContentState
}
Expand Down Expand Up @@ -1781,8 +1781,12 @@ public class BrowserViewController: UIViewController {
break
}

if tab.secureContentState == .secure && !webView.hasOnlySecureContent {
tab.secureContentState = .insecure
if tab.secureContentState == .secure, !webView.hasOnlySecureContent,
tab.url?.origin == tab.webView?.url?.origin {
if let url = tab.webView?.url, url.isReaderModeURL {
break
}
tab.secureContentState = .mixedContent
}

if tabManager.selectedTab === tab {
Expand All @@ -1801,9 +1805,9 @@ public class BrowserViewController: UIViewController {
let internalUrl = InternalURL(url),
(internalUrl.isAboutURL || internalUrl.isAboutHomeURL) {

tab.secureContentState = .localHost
tab.secureContentState = .localhost
if tabManager.selectedTab === tab {
updateToolbarSecureContentState(.localHost)
updateToolbarSecureContentState(.localhost)
}
break
}
Expand All @@ -1813,27 +1817,29 @@ public class BrowserViewController: UIViewController {
internalUrl.isErrorPage {

if ErrorPageHelper.certificateError(for: url) != 0 {
tab.secureContentState = .insecure
if tabManager.selectedTab === tab {
updateToolbarSecureContentState(.insecure)
}
break
tab.secureContentState = .invalidCert
} else {
tab.secureContentState = .missingSSL
}
if tabManager.selectedTab === tab {
updateToolbarSecureContentState(tab.secureContentState)
}
break
}

if url.isReaderModeURL || InternalURL.isValid(url: url) {
tab.secureContentState = .unknown
tab.secureContentState = .localhost
if tabManager.selectedTab === tab {
updateToolbarSecureContentState(.unknown)
updateToolbarSecureContentState(.localhost)
}
break
}

// All our checks failed, we show the page as insecure
tab.secureContentState = .insecure
tab.secureContentState = .missingSSL
} else {
// When there is no URL, it's likely a new tab.
tab.secureContentState = .localHost
tab.secureContentState = .localhost
}

if tabManager.selectedTab === tab {
Expand All @@ -1844,7 +1850,7 @@ public class BrowserViewController: UIViewController {

guard let scheme = tab.webView?.url?.scheme,
let host = tab.webView?.url?.host else {
tab.secureContentState = .insecure
tab.secureContentState = .unknown
self.updateURLBar()
return
}
Expand Down Expand Up @@ -1872,10 +1878,10 @@ public class BrowserViewController: UIViewController {
try await BraveCertificateUtils.evaluateTrust(serverTrust, for: host)
tab.secureContentState = .secure
} else {
tab.secureContentState = .insecure
tab.secureContentState = .invalidCert
}
} catch {
tab.secureContentState = .insecure
tab.secureContentState = .invalidCert
}

Task { @MainActor in
Expand Down Expand Up @@ -1930,7 +1936,7 @@ public class BrowserViewController: UIViewController {
updateToolbarSecureContentState(tab.secureContentState)
}

let isPage = tab.url?.displayURL?.isWebPage() ?? false
let isPage = tab.url?.isWebPage() ?? false
navigationToolbar.updatePageStatus(isPage)
updateWebViewPageZoom(tab: tab)
}
Expand Down Expand Up @@ -2111,6 +2117,22 @@ public class BrowserViewController: UIViewController {
activities.append(sendTabToSelfActivity)
}

if let tab = self.tabManager.selectedTab, tab.secureContentState.shouldDisplayWarning {
if tab.readerModeAvailableOrActive {
// If the reader mode button is occluded due to a secure content state warning add it as an activity
activities.append(
BasicMenuActivity(
title: Strings.toggleReaderMode,
braveSystemImage: "leo.product.speedreader",
callback: { [weak self] in
self?.toggleReaderMode()
}
)
)
}
// Any other buttons on the leading side of the location view should be added here as well
}

let findInPageActivity = FindInPageActivity() { [unowned self] in
if #available(iOS 16.0, *), let findInteraction = self.tabManager.selectedTab?.webView?.findInteraction {
findInteraction.searchText = ""
Expand Down Expand Up @@ -2244,6 +2266,13 @@ public class BrowserViewController: UIViewController {
activities.append(addSearchEngineActivity)
}

if let secureState = tabManager.selectedTab?.secureContentState, secureState != .missingSSL && secureState != .unknown {
let displayCertificateActivity = BasicMenuActivity(title: Strings.displayCertificate, braveSystemImage: "leo.lock.plain") { [weak self] in
self?.displayPageCertificateInfo()
}
activities.append(displayCertificateActivity)
}

activities.append(ReportWebCompatibilityIssueActivity() { [weak self] in
self?.showSubmitReportView(for: url)
})
Expand Down Expand Up @@ -2455,6 +2484,20 @@ public class BrowserViewController: UIViewController {
}
}

func toggleReaderMode() {
guard let tab = tabManager.selectedTab else { return }
if let readerMode = tab.getContentScript(name: ReaderModeScriptHandler.scriptName) as? ReaderModeScriptHandler {
switch readerMode.state {
case .available:
enableReaderMode()
case .active:
disableReaderMode()
case .unavailable:
break
}
}
}

func handleToolbarVisibilityStateChange(
_ state: ToolbarVisibilityViewModel.ToolbarState,
progress: CGFloat?
Expand Down Expand Up @@ -2766,7 +2809,7 @@ extension BrowserViewController: TabDelegate {
contentController: vc,
contentSizeBehavior: .preferredContentSize)
popover.addsConvenientDismissalMargins = false
popover.present(from: topToolbar.locationView.rewardsButton, on: self)
popover.present(from: topToolbar.rewardsButton, on: self)
popover.popoverDidDismiss = { _ in
// This gets called if popover is dismissed by user gesture
// This does not conflict with 'Enable Rewards' button.
Expand All @@ -2783,7 +2826,7 @@ extension BrowserViewController: TabDelegate {
let popover2 = PopoverController(
contentController: vc2,
contentSizeBehavior: .preferredContentSize)
popover2.present(from: self.topToolbar.locationView.rewardsButton, on: self)
popover2.present(from: self.topToolbar.rewardsButton, on: self)
}

vc.linkTapped = { [unowned self] request in
Expand Down Expand Up @@ -3393,3 +3436,70 @@ extension BrowserViewController: IAPObserverDelegate {
}
}
}

// Certificate info
extension BrowserViewController {

func displayPageCertificateInfo() {
guard let webView = tabManager.selectedTab?.webView else {
Logger.module.error("Invalid WebView")
return
}

let getServerTrustForErrorPage = { () -> SecTrust? in
do {
if let url = webView.url {
return try ErrorPageHelper.serverTrust(from: url)
}
} catch {
Logger.module.error("\(error.localizedDescription)")
}

return nil
}

guard let trust = webView.serverTrust ?? getServerTrustForErrorPage() else {
return
}

let host = webView.url?.host

Task.detached {
let serverCertificates: [SecCertificate] = SecTrustCopyCertificateChain(trust) as? [SecCertificate] ?? []

// TODO: Instead of showing only the first cert in the chain,
// have a UI that allows users to select any certificate in the chain (similar to Desktop browsers)
if let serverCertificate = serverCertificates.first,
diracdeltas marked this conversation as resolved.
Show resolved Hide resolved
let certificate = BraveCertificateModel(certificate: serverCertificate) {

var errorDescription: String?

do {
try await BraveCertificateUtils.evaluateTrust(trust, for: host)
} catch {
Logger.module.error("\(error.localizedDescription)")

// Remove the common-name from the first part of the error message
// This is because the certificate viewer already displays it.
// If it doesn't match, it won't be removed, so this is fine.
errorDescription = error.localizedDescription
if let range = errorDescription?.range(of: "“\(certificate.subjectName.commonName)” ") ??
errorDescription?.range(of: "\"\(certificate.subjectName.commonName)\" ") {
errorDescription = errorDescription?.replacingCharacters(in: range, with: "").capitalizeFirstLetter
}
}

await MainActor.run { [errorDescription] in
if #available(iOS 16.0, *) {
// System components sit on top so we want to dismiss it
webView.findInteraction?.dismissFindNavigator()
}
let certificateViewController = CertificateViewController(certificate: certificate, evaluationError: errorDescription)
certificateViewController.modalPresentationStyle = .pageSheet
certificateViewController.sheetPresentationController?.detents = [.medium(), .large()]
self.present(certificateViewController, animated: true)
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ extension BrowserViewController {
func updateRewardsButtonState() {
if !isViewLoaded { return }
if !BraveRewards.isAvailable {
self.topToolbar.locationView.rewardsButton.isHidden = true
self.topToolbar.rewardsButton.isHidden = true
return
}
self.topToolbar.locationView.rewardsButton.isHidden = Preferences.Rewards.hideRewardsIcon.value || privateBrowsingManager.isPrivateBrowsing
self.topToolbar.locationView.rewardsButton.iconState = Preferences.Rewards.rewardsToggledOnce.value ? (rewards.isEnabled || rewards.isCreatingWallet ? .enabled : .disabled) : .initial
self.topToolbar.rewardsButton.isHidden = Preferences.Rewards.hideRewardsIcon.value || privateBrowsingManager.isPrivateBrowsing
self.topToolbar.rewardsButton.iconState = Preferences.Rewards.rewardsToggledOnce.value ? (rewards.isEnabled || rewards.isCreatingWallet ? .enabled : .disabled) : .initial
}

func showBraveRewardsPanel() {
Expand All @@ -44,7 +44,7 @@ extension BrowserViewController {

Preferences.FullScreenCallout.rewardsCalloutCompleted.value = true
present(controller, animated: true)
topToolbar.locationView.rewardsButton.iconState = Preferences.Rewards.rewardsToggledOnce.value ? (rewards.isEnabled || rewards.isCreatingWallet ? .enabled : .disabled) : .initial
topToolbar.rewardsButton.iconState = Preferences.Rewards.rewardsToggledOnce.value ? (rewards.isEnabled || rewards.isCreatingWallet ? .enabled : .disabled) : .initial
return
}

Expand All @@ -70,7 +70,7 @@ extension BrowserViewController {

let popover = PopoverController(contentController: braveRewardsPanel)
popover.addsConvenientDismissalMargins = false
popover.present(from: topToolbar.locationView.rewardsButton, on: self)
popover.present(from: topToolbar.rewardsButton, on: self)
popover.popoverDidDismiss = { [weak self] _ in
guard let self = self else { return }
if let tabId = self.tabManager.selectedTab?.rewardsId, self.rewards.rewardsAPI?.selectedTabId == 0 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,10 @@ extension BrowserViewController {
guard presentedViewController == nil else {
return
}

let frame = view.convert(
topToolbar.locationView.urlTextField.frame,
from: topToolbar.locationView).insetBy(dx: -7.0, dy: -1.0)
topToolbar.locationView.frame,
from: topToolbar.locationView).insetBy(dx: -1.0, dy: -1.0)

// Present the popover
let controller = WelcomeOmniBoxOnboardingController()
Expand All @@ -95,7 +95,7 @@ extension BrowserViewController {

presentPopoverContent(
using: controller,
with: frame, cornerRadius: 6.0,
with: frame, cornerRadius: topToolbar.locationContainer.layer.cornerRadius,
didDismiss: { [weak self] in
guard let self = self else { return }

Expand Down Expand Up @@ -275,12 +275,12 @@ extension BrowserViewController {
}

let popover = PopoverController(contentController: controller)
popover.previewForOrigin = .init(view: topToolbar.locationView.shieldsButton, action: { [weak self] popover in
popover.previewForOrigin = .init(view: topToolbar.shieldsButton, action: { [weak self] popover in
popover.dismissPopover() {
self?.presentBraveShieldsViewController()
}
})
popover.present(from: topToolbar.locationView.shieldsButton, on: self)
popover.present(from: topToolbar.shieldsButton, on: self)

popover.popoverDidDismiss = { [weak self] _ in
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ extension BrowserViewController {

let popover = PopoverController(contentController: controller)
popover.addsConvenientDismissalMargins = false
popover.previewForOrigin = .init(view: topToolbar.locationView.shieldsButton)
popover.present(from: topToolbar.locationView.shieldsButton, on: self)
popover.previewForOrigin = .init(view: topToolbar.shieldsButton)
popover.present(from: topToolbar.shieldsButton, on: self)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,7 @@ extension BrowserViewController: TabManagerDelegate {
toolbar?.searchButton.menu = UIMenu(title: "", identifier: nil, children: addTabMenuActionList)

// Update Actions for Add-Tab Button
topToolbar.addTabButton.menu = UIMenu(title: "", identifier: nil, children: addTabMenuActionList)
toolbar?.addTabButton.menu = UIMenu(title: "", identifier: nil, children: addTabMenuActionList)
}
}
Loading