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

Commit

Permalink
Fix #511: Youtube intermittent ads (#2655)
Browse files Browse the repository at this point in the history
  • Loading branch information
Brandon-T authored Jul 3, 2020
1 parent ce39001 commit 3a61a6d
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 3 deletions.
4 changes: 4 additions & 0 deletions Client.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,7 @@
5E46C37C234FB9A700ACA8C1 /* self-signed.cer in Resources */ = {isa = PBXBuildFile; fileRef = 5E46C37B234FB9A700ACA8C1 /* self-signed.cer */; };
5E4845C022DE381200372022 /* WindowRenderHelper.js in Resources */ = {isa = PBXBuildFile; fileRef = 5E4845BF22DE381200372022 /* WindowRenderHelper.js */; };
5E4845C222DE3DF800372022 /* WindowRenderHelperScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E4845C122DE3DF800372022 /* WindowRenderHelperScript.swift */; };
5E4E078324A0E4D700B01720 /* YoutubeAdblock.js in Resources */ = {isa = PBXBuildFile; fileRef = 5E4E078224A0E4D700B01720 /* YoutubeAdblock.js */; };
5E612A8C234B7FC1007D12B5 /* OnboardingAdsAvailableController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E1D8C66232BE43100BDE662 /* OnboardingAdsAvailableController.swift */; };
5E612A8E234B7FC8007D12B5 /* OnboardingAdsAvailableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E1D8C68232BE47A00BDE662 /* OnboardingAdsAvailableView.swift */; };
5E612A8F234B7FCA007D12B5 /* OnboardingRewardsAgreementViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E1D8C6A232BF95200BDE662 /* OnboardingRewardsAgreementViewController.swift */; };
Expand Down Expand Up @@ -2223,6 +2224,7 @@
5E46C37B234FB9A700ACA8C1 /* self-signed.cer */ = {isa = PBXFileReference; lastKnownFileType = file; path = "self-signed.cer"; sourceTree = "<group>"; };
5E4845BF22DE381200372022 /* WindowRenderHelper.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = WindowRenderHelper.js; sourceTree = "<group>"; };
5E4845C122DE3DF800372022 /* WindowRenderHelperScript.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowRenderHelperScript.swift; sourceTree = "<group>"; };
5E4E078224A0E4D700B01720 /* YoutubeAdblock.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = YoutubeAdblock.js; sourceTree = "<group>"; };
5E6683A823D61CF7005B3A6C /* NTPDownloader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NTPDownloader.swift; sourceTree = "<group>"; };
5E77F9DC236BB68700E1649C /* AttestationDebugger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttestationDebugger.swift; sourceTree = "<group>"; };
5E856FE5235E08110094E113 /* Cryptography.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = Cryptography.swift; sourceTree = "<group>"; tabWidth = 2; };
Expand Down Expand Up @@ -4475,6 +4477,7 @@
5E4845BF22DE381200372022 /* WindowRenderHelper.js */,
5EB57D0122FDC0CB00A07325 /* FullscreenHelper.js */,
F9B23EE123F61173000EB3D8 /* PaymentRequest.js */,
5E4E078224A0E4D700B01720 /* YoutubeAdblock.js */,
);
path = UserScripts;
sourceTree = "<group>";
Expand Down Expand Up @@ -5872,6 +5875,7 @@
E4B7B7861A793CF20022C5E0 /* FiraSans-UltraLight.ttf in Resources */,
E4B7B77D1A793CF20022C5E0 /* FiraSans-Regular.ttf in Resources */,
4422D55221BFFB7E00BF1855 /* make_unicode_casefold.py in Resources */,
5E4E078324A0E4D700B01720 /* YoutubeAdblock.js in Resources */,
E4B7B7791A793CF20022C5E0 /* FiraSans-Light.ttf in Resources */,
5E3477E922D7771700B0D5F8 /* ResourceDownloader.js in Resources */,
F99505FF22937E3900CC6543 /* U2F-low-level.js in Resources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,14 @@ extension BrowserViewController: WKNavigationDelegate {
decisionHandler(.cancel)
return
}

let isPrivateBrowsing = PrivateBrowsingManager.shared.isPrivateBrowsing

if url.baseDomain == "youtube.com" {
let domain = Domain.getOrCreate(forUrl: url, persistent: !isPrivateBrowsing)
tabManager[webView]?.userScriptManager?.isYoutubeAdblockEnabled = domain.isShieldExpected(.AdblockAndTp, considerAllShieldsOption: true)
}

// This is the normal case, opening a http or https url, which we handle by loading them in this WKWebView. We
// always allow this. Additionally, data URIs are also handled just like normal web pages.

Expand Down
3 changes: 2 additions & 1 deletion Client/Frontend/Browser/Tab.swift
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,8 @@ class Tab: NSObject {
isFingerprintingProtectionEnabled: Preferences.Shields.fingerprintingProtection.value,
isCookieBlockingEnabled: Preferences.Privacy.blockAllCookies.value,
isU2FEnabled: webView.hasOnlySecureContent,
isPaymentRequestEnabled: webView.hasOnlySecureContent)
isPaymentRequestEnabled: webView.hasOnlySecureContent,
isYoutubeAdblockEnabled: false)
tabDelegate?.tab?(self, didCreateWebView: webView)
}
}
Expand Down
34 changes: 32 additions & 2 deletions Client/Frontend/Browser/UserScriptManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,21 @@ class UserScriptManager {
}
}

init(tab: Tab, isFingerprintingProtectionEnabled: Bool, isCookieBlockingEnabled: Bool, isU2FEnabled: Bool, isPaymentRequestEnabled: Bool) {
// Whether or not the Adblock shields are enabled
var isYoutubeAdblockEnabled: Bool {
didSet {
if oldValue == isYoutubeAdblockEnabled { return }
reloadUserScripts()
}
}

init(tab: Tab, isFingerprintingProtectionEnabled: Bool, isCookieBlockingEnabled: Bool, isU2FEnabled: Bool, isPaymentRequestEnabled: Bool, isYoutubeAdblockEnabled: Bool) {
self.tab = tab
self.isFingerprintingProtectionEnabled = isFingerprintingProtectionEnabled
self.isCookieBlockingEnabled = isCookieBlockingEnabled
self.isU2FEnabled = isU2FEnabled
self.isPaymentRequestEnabled = isPaymentRequestEnabled
self.isYoutubeAdblockEnabled = isYoutubeAdblockEnabled
reloadUserScripts()
}

Expand Down Expand Up @@ -187,7 +196,7 @@ class UserScriptManager {

//Verify that the application itself is making a call to the JS script instead of other scripts on the page.
//This variable will be unique amongst scripts loaded in the page.
//When the script is called, the token is provided in order to access teh script variable.
//When the script is called, the token is provided in order to access the script variable.
var alteredSource = source
let token = UserScriptManager.securityToken.uuidString.replacingOccurrences(of: "-", with: "", options: .literal)
alteredSource = alteredSource.replacingOccurrences(of: "$<possiblySupportedFunctions>", with: "PSF\(token)", options: .literal)
Expand All @@ -197,6 +206,23 @@ class UserScriptManager {

return WKUserScript(source: alteredSource, injectionTime: .atDocumentStart, forMainFrameOnly: false)
}()

private let youtubeAdblockJSScript: WKUserScript? = {
guard let path = Bundle.main.path(forResource: "YoutubeAdblock", ofType: "js"), let source = try? String(contentsOfFile: path) else {
log.error("Failed to load YoutubeAdblock.js")
return nil
}

//Verify that the application itself is making a call to the JS script instead of other scripts on the page.
//This variable will be unique amongst scripts loaded in the page.
//When the script is called, the token is provided in order to access the script variable.
var alteredSource = source
let token = UserScriptManager.securityToken.uuidString.replacingOccurrences(of: "-", with: "", options: .literal)
alteredSource = alteredSource.replacingOccurrences(of: "$<prunePaths>", with: "ABS\(token)", options: .literal)
alteredSource = alteredSource.replacingOccurrences(of: "$<findOwner>", with: "ABS\(token)", options: .literal)

return WKUserScript(source: alteredSource, injectionTime: .atDocumentStart, forMainFrameOnly: false)
}()

private func reloadUserScripts() {
tab?.webView?.configuration.userContentController.do {
Expand Down Expand Up @@ -230,6 +256,10 @@ class UserScriptManager {
$0.addUserScript(script)
}

if isYoutubeAdblockEnabled, let script = youtubeAdblockJSScript {
$0.addUserScript(script)
}

#if !NO_SKUS
if isPaymentRequestEnabled, let script = PaymentRequestUserScript {
$0.addUserScript(script)
Expand Down
36 changes: 36 additions & 0 deletions Client/Frontend/UserContent/UserScripts/YoutubeAdblock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2020 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/.

(function() {
const $<prunePaths> = ['playerResponse.adPlacements', 'playerResponse.playerAds', 'adPlacements', 'playerAds'];
const $<findOwner> = function(root, path) {
let owner = root;
let chain = path;
while(true) {
if (owner instanceof Object === false) { return; }
const pos = chain.indexOf('.');
if (pos === -1) {
return owner.hasOwnProperty(chain)? [owner, chain]: undefined;
}
const prop = chain.slice(0, pos);
if (owner.hasOwnProperty(prop) === false) { return; }
owner = owner[prop];
chain = chain.slice(pos + 1);
}
};

JSON.parse = new Proxy(JSON.parse, {
apply: function() {
const r = Reflect.apply(...arguments);
for (const path of $<prunePaths>) {
const details = $<findOwner>(r, path);
if (details !== undefined) {
delete details[0][details[1]];
}
}
return r;
},
});
})();

0 comments on commit 3a61a6d

Please sign in to comment.