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

Commit

Permalink
Add domain blocking "Proceed" and "Go Back" actions (#8628)
Browse files Browse the repository at this point in the history
  • Loading branch information
cuba authored Feb 2, 2024
1 parent c13f303 commit 1e3520f
Show file tree
Hide file tree
Showing 9 changed files with 189 additions and 23 deletions.
23 changes: 23 additions & 0 deletions Sources/Brave/Assets/Interstitial Pages/Pages/BlockedDomain.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,29 @@ <h1>%blocked_title%</h1>
<h2>%blocked_subtitle%</h2>
<pre class="domain">%blocked_domain%</pre>
<p class="description">%blocked_description%</p>
<div class="actions">
<button id="proceed-action" class="main-action">%proceed_action%</button>
<button id="go-back-action" class="secondary-action">%go_back_action%</button>
</div>
</div>

<script>
(() => {
const sendAction = (action) => {
webkit.messageHandlers["%message_handler%"].postMessage({
"securityToken": "%security_token%",
"action": action
})
}

document.getElementById('proceed-action').onclick = () => {
sendAction('didProceed')
}

document.getElementById('go-back-action').onclick = () => {
sendAction('didGoBack')
}
})()
</script>
</body>
</html>
Empty file.
62 changes: 54 additions & 8 deletions Sources/Brave/Assets/Interstitial Pages/Styles/BlockedDomain.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,20 @@ html {
}

.post {
padding-top: max(25px, env(safe-area-inset-top));
padding-bottom: max(25px, env(safe-area-inset-bottom));
padding-left: max(25px, env(safe-area-inset-left));
padding-right: max(25px, env(safe-area-inset-right));
padding-top: max(25px, env(safe-area-inset-top));
padding-bottom: max(25px, env(safe-area-inset-bottom));
padding-left: max(25px, env(safe-area-inset-left));
padding-right: max(25px, env(safe-area-inset-right));
}

.background {
background-color: #FFFFFF;
background-color: #FFFFFF;
}

.icon {
width: 40px;
height: 40px;
margin-bottom: 1em;
width: 40px;
height: 40px;
margin-bottom: 1em;
}

h1 {
Expand Down Expand Up @@ -76,6 +76,40 @@ h2 {
align-content: flex-start;
}

.actions {
margin-top: 48px;
display: flex;
flex-wrap: wrap;
flex-direction: column;
align-content: flex-start;
justify-content: space-between;
}

button {
font-family: SFProDisplay-Medium, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
font-size: 15px;
font-weight: 600;
line-height: 20px;
letter-spacing: -0.2px;
text-align: center;
padding: 12px 16px 12px 16px;
border-radius: 12px;
margin: 4px 0;
width: 100%;
}

.main-action {
color: white;
background: #3F39E8;
border: 1px solid #3F39E8;
}

.secondary-action {
color: #3F39E8;
background: #545FF800;
border: 1px solid #545FF866;
}

/** Center the content for iPads **/
@media (min-width: 600px) and (min-height: 600px) {
.icon {
Expand Down Expand Up @@ -117,6 +151,14 @@ h2 {
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}

.actions {
flex-direction: row-reverse;
}

button {
width: auto;
}
}


Expand All @@ -132,4 +174,8 @@ h2 {
.description, .domain {
color: #DBDEE2;
}

.secondary-action {
color: #7C91FF;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -355,22 +355,24 @@ extension BrowserViewController: WKNavigationDelegate {
if navigationAction.targetFrame?.isMainFrame == true {
tab?.updateUserAgent(webView, newURL: requestURL)

let domain = Domain.getOrCreate(forUrl: requestURL, persistent: !isPrivateBrowsing)

let shouldBlock = await AdBlockStats.shared.shouldBlock(
requestURL: requestURL, sourceURL: requestURL, resourceType: .document,
isAggressiveMode: domain.blockAdsAndTrackingLevel.isAggressive
)

if shouldBlock, let escapingURL = requestURL.absoluteString.escape() {
var components = URLComponents(string: InternalURL.baseUrl)
components?.path = "/\(InternalURL.Path.blocked.rawValue)"
components?.queryItems = [URLQueryItem(name: "url", value: escapingURL)]
if let etldP1 = requestURL.baseDomain, tab?.proceedAnywaysDomainList.contains(etldP1) == false {
let domain = Domain.getOrCreate(forUrl: requestURL, persistent: !isPrivateBrowsing)

if let url = components?.url {
let request = PrivilegedRequest(url: url) as URLRequest
tab?.loadRequest(request)
return (.cancel, preferences)
let shouldBlock = await AdBlockStats.shared.shouldBlock(
requestURL: requestURL, sourceURL: requestURL, resourceType: .document,
isAggressiveMode: domain.blockAdsAndTrackingLevel.isAggressive
)

if shouldBlock, let escapingURL = requestURL.absoluteString.escape() {
var components = URLComponents(string: InternalURL.baseUrl)
components?.path = "/\(InternalURL.Path.blocked.rawValue)"
components?.queryItems = [URLQueryItem(name: "url", value: escapingURL)]

if let url = components?.url {
let request = PrivilegedRequest(url: url) as URLRequest
tab?.loadRequest(request)
return (.cancel, preferences)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2503,6 +2503,7 @@ extension BrowserViewController: TabDelegate {
ReaderModeScriptHandler(tab: tab),
ErrorPageHelper(certStore: profile.certStore),
SessionRestoreScriptHandler(tab: tab),
BlockedDomainScriptHandler(tab: tab),
PrintScriptHandler(browserController: self, tab: tab),
CustomSearchScriptHandler(tab: tab),
NightModeScriptHandler(tab: tab),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ public class BlockedDomainHandler: InternalSchemeResponse {
.replacingOccurrences(of: "%blocked_subtitle%", with: Strings.Shields.domainBlockedPageMessage)
.replacingOccurrences(of: "%blocked_domain%", with: originalURL.domainURL.absoluteDisplayString)
.replacingOccurrences(of: "%blocked_description%", with: Strings.Shields.domainBlockedPageDescription)
.replacingOccurrences(of: "%proceed_action%", with: Strings.Shields.domainBlockedProceedAction)
.replacingOccurrences(of: "%go_back_action%", with: Strings.Shields.domainBlockedGoBackAction)
.replacingOccurrences(of: "%message_handler%", with: BlockedDomainScriptHandler.messageHandlerName)
.replacingOccurrences(of: "%security_token%", with: UserScriptManager.securityToken)

if #available(iOS 16.0, *) {
html = html?.replacingOccurrences(of: "<html lang=\"en\">", with: "<html lang=\"\(Locale.current.language.minimalIdentifier)\">")
Expand Down
3 changes: 3 additions & 0 deletions Sources/Brave/Frontend/Browser/Tab.swift
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,9 @@ class Tab: NSObject {
}
return favicon
}

/// A list of domains that we want to proceed to anyways regardless of any ad-blocking
var proceedAnywaysDomainList: Set<String> = []

var canGoBack: Bool {
return webView?.canGoBack ?? false
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright 2023 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 https://mozilla.org/MPL/2.0/.

import Foundation
import Shared
import WebKit

class BlockedDomainScriptHandler: TabContentScript {
private weak var tab: Tab?

required init(tab: Tab) {
self.tab = tab
}

static let scriptName = "BlockedDomainScript"
static let scriptId = UUID().uuidString
static let messageHandlerName = "\(scriptName)_\(messageUUID)"
static let scriptSandbox: WKContentWorld = .page
static let userScript: WKUserScript? = nil

func userContentController(_ userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage, replyHandler: (Any?, String?) -> Void) {
defer { replyHandler(nil, nil) }

if !verifyMessage(message: message, securityToken: UserScriptManager.securityToken) {
assertionFailure("Missing required security token.")
return
}

guard let params = message.body as? [String: AnyObject], let action = params["action"] as? String else {
assertionFailure("Missing required params.")
return
}

switch action {
case "didProceed":
blockedDomainDidProceed()
case "didGoBack":
blockedDomainDidGoBack()
default:
assertionFailure("Unhandled action `\(action)`")
}
}

private func blockedDomainDidProceed() {
guard let url = tab?.url?.stippedInternalURL, let etldP1 = url.baseDomain else {
assertionFailure("There should be no way this method can be triggered if the tab is not on an internal url")
return
}

let request = URLRequest(url: url)
tab?.proceedAnywaysDomainList.insert(etldP1)
tab?.loadRequest(request)
}

private func blockedDomainDidGoBack() {
guard let url = tab?.url?.stippedInternalURL else {
assertionFailure("There should be no way this method can be triggered if the tab is not on an internal url")
return
}

guard let listItem = tab?.backList?.reversed().first(where: { $0.url != url }) else {
// How is this even possible?
// All testing indicates no, so we will not handle.
// If we find it is, then we need to disable or hide the "Go Back" button in these cases.
// But this would require heavy changes or ugly mechanisms to InternalSchemeHandler.
return
}

tab?.goToBackForwardListItem(listItem)
}
}
14 changes: 14 additions & 0 deletions Sources/BraveShields/ShieldStrings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -195,4 +195,18 @@ public extension Strings.Shields {
value: "Because you requested to aggressively block trackers and ads, Brave is blocking this site before the first network connection.",
comment: "A description in the warning page that appears when a page was blocked"
)

/// Text for a button in a blocked page info screen that allows you to proceed regardless of the privacy warning
static let domainBlockedProceedAction = NSLocalizedString(
"DomainBlockedProceedAction", tableName: "BraveShared", bundle: .module,
value: "Proceed",
comment: "Text for a button in a blocked page info screen that allows you to proceed regardless of the privacy warning"
)

/// A description in the warning page that appears when a page was blocked
static let domainBlockedGoBackAction = NSLocalizedString(
"DomainBlockedGoBackAction", tableName: "BraveShared", bundle: .module,
value: "Go Back",
comment: "Text for a button in a blocked page info screen that takes you back where you came from"
)
}

0 comments on commit 1e3520f

Please sign in to comment.