Skip to content

Commit

Permalink
Add NavigationPreferences CustomHeaderFields (#2147)
Browse files Browse the repository at this point in the history
  • Loading branch information
mallexxx authored Feb 7, 2024
1 parent 9148c19 commit 23e491d
Showing 22 changed files with 94 additions and 77 deletions.
2 changes: 1 addition & 1 deletion DuckDuckGo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
@@ -13259,7 +13259,7 @@
repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit";
requirement = {
kind = exactVersion;
version = 104.1.1;
version = 104.2.0;
};
};
AA06B6B52672AF8100F541C5 /* XCRemoteSwiftPackageReference "Sparkle" */ = {
Original file line number Diff line number Diff line change
@@ -14,8 +14,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/duckduckgo/BrowserServicesKit",
"state" : {
"revision" : "3b10ff8d5d433a4eb45a1d4d25a348033f5102c1",
"version" : "104.1.1"
"revision" : "d0741645b44448d655b1f56eba464f463f294e4f",
"version" : "104.2.0"
}
},
{
12 changes: 0 additions & 12 deletions DuckDuckGo/Localizable.xcstrings
Original file line number Diff line number Diff line change
@@ -8498,18 +8498,6 @@
"Settings…" : {
"comment" : "Menu item"
},
"settings.hide-home-shortcut" : {
"comment" : "Settings Optionm to set Home Button visibility",
"extractionState" : "extracted_with_value",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "new",
"value" : "Show Home Button in Toolbar"
}
}
}
},
"share.menu.item" : {
"comment" : "Menu item title",
"extractionState" : "extracted_with_value",
18 changes: 14 additions & 4 deletions DuckDuckGo/Tab/Navigation/SerpHeadersNavigationResponder.swift
Original file line number Diff line number Diff line change
@@ -26,19 +26,29 @@ struct SerpHeadersNavigationResponder: NavigationResponder {
]

func decidePolicy(for navigationAction: NavigationAction, preferences: inout NavigationPreferences) async -> NavigationActionPolicy? {
// add X-DuckDuckGo-Client header for main-frame SERP navigations
guard navigationAction.isForMainFrame,
navigationAction.url.isDuckDuckGo,
Self.headers.contains(where: { navigationAction.request.value(forHTTPHeaderField: $0.key) == nil }),
!navigationAction.navigationType.isBackForward
else {
Self.headers.contains(where: { navigationAction.request.value(forHTTPHeaderField: $0.key) == nil }) else {
return .next
}

// do we support WKWebPagePreferences headers modification?
if NavigationPreferences.customHeadersSupported,
let customHeaders = CustomHeaderFields(fields: Self.headers) {
preferences.customHeaders = [customHeaders]
// ok, proceed
return .next
}

// no WKWebPagePreferences custom headers:
// make sure we‘re not erasing forward history and redirect the request with modified headers
guard !navigationAction.navigationType.isBackForward else { return .next }

var request = navigationAction.request
for (key, value) in Self.headers {
request.setValue(value, forHTTPHeaderField: key)
}

return .redirectInvalidatingBackItemIfNeeded(navigationAction) { navigator in
navigator.load(request)
}
2 changes: 1 addition & 1 deletion LocalPackages/DataBrokerProtection/Package.swift
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@ let package = Package(
targets: ["DataBrokerProtection"])
],
dependencies: [
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "104.1.1"),
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "104.2.0"),
.package(path: "../PixelKit"),
.package(path: "../SwiftUIExtensions"),
.package(path: "../XPCHelper")
2 changes: 1 addition & 1 deletion LocalPackages/LoginItems/Package.swift
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@ let package = Package(
),
],
dependencies: [
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "104.1.1"),
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "104.2.0"),
],
targets: [
.target(
2 changes: 1 addition & 1 deletion LocalPackages/NetworkProtectionMac/Package.swift
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@ let package = Package(
.library(name: "NetworkProtectionUI", targets: ["NetworkProtectionUI"])
],
dependencies: [
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "104.1.1"),
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "104.2.0"),
.package(path: "../XPCHelper"),
.package(path: "../SwiftUIExtensions")
],
2 changes: 1 addition & 1 deletion LocalPackages/PixelKit/Package.swift
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ let package = Package(
)
],
dependencies: [
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "104.1.1"),
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "104.2.0"),
],
targets: [
.target(
2 changes: 1 addition & 1 deletion LocalPackages/Subscription/Package.swift
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@ let package = Package(
targets: ["Subscription"]),
],
dependencies: [
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "104.1.1"),
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "104.2.0"),
],
targets: [
.target(
2 changes: 1 addition & 1 deletion LocalPackages/SwiftUIExtensions/Package.swift
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ let package = Package(
.library(name: "PreferencesViews", targets: ["PreferencesViews"]),
],
dependencies: [
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "104.1.1"),
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "104.2.0"),
],
targets: [
.target(
2 changes: 1 addition & 1 deletion LocalPackages/SyncUI/Package.swift
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@ let package = Package(
],
dependencies: [
.package(path: "../SwiftUIExtensions"),
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "104.1.1"),
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "104.2.0"),
],
targets: [
.target(
2 changes: 1 addition & 1 deletion LocalPackages/SystemExtensionManager/Package.swift
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ let package = Package(
),
],
dependencies: [
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "104.1.1"),
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "104.2.0"),
],
targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
2 changes: 1 addition & 1 deletion LocalPackages/XPCHelper/Package.swift
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@ let package = Package(
.library(name: "XPCHelper", targets: ["XPCHelper"]),
],
dependencies: [
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "104.1.1"),
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "104.2.0"),
],
targets: [
.target(
4 changes: 2 additions & 2 deletions UnitTests/Fireproofing/FireproofDomainsTests.swift
Original file line number Diff line number Diff line change
@@ -70,7 +70,7 @@ final class FireproofDomainsTests: XCTestCase {
}

func testWhenFireproofedDomainsInUserDefaultsThenMigrationIsPerformed() {
var udw = UserDefaultsWrapper<[String]?>(key: .fireproofDomains, defaultValue: nil)
let udw = UserDefaultsWrapper<[String]?>(key: .fireproofDomains, defaultValue: nil)
udw.wrappedValue = ["example.com", "www.secondexample.com"]
XCTAssertEqual(logins.fireproofDomains.sorted(), ["example.com", "secondexample.com"])
XCTAssertNil(udw.wrappedValue)
@@ -86,7 +86,7 @@ final class FireproofDomainsTests: XCTestCase {
}

func testWhenFireproofedDomainsInStoreThenTheyAreLoaded() {
var udw = UserDefaultsWrapper<[String]?>(key: .fireproofDomains, defaultValue: nil)
let udw = UserDefaultsWrapper<[String]?>(key: .fireproofDomains, defaultValue: nil)
udw.wrappedValue = []
store.domains = ["example.com": .init(), "secondexample.com": .init()]
XCTAssertEqual(logins.fireproofDomains.sorted(), ["example.com", "secondexample.com"])
2 changes: 1 addition & 1 deletion UnitTests/HomePage/ContinueSetUpModelTests.swift
Original file line number Diff line number Diff line change
@@ -234,7 +234,7 @@ final class ContinueSetUpModelTests: XCTestCase {
}

@MainActor func testWhenInitializedNotForTheFirstTimeTheMatrixHasAllElementsInTheRightOrder() {
var homePageIsFirstSession = UserDefaultsWrapper<Bool>(key: .homePageIsFirstSession, defaultValue: true)
let homePageIsFirstSession = UserDefaultsWrapper<Bool>(key: .homePageIsFirstSession, defaultValue: true)
homePageIsFirstSession.wrappedValue = false
vm = HomePage.Models.ContinueSetUpModel.fixture(appGroupUserDefaults: userDefaults)
vm.shouldShowAllFeatures = true
2 changes: 1 addition & 1 deletion UnitTests/HomePage/DataImportProviderTests.swift
Original file line number Diff line number Diff line change
@@ -108,7 +108,7 @@ final class DataImportProviderTests: XCTestCase {
}

func testWhenNoPasswordsAndNoBookmarksDetectableAndSuccessImportThenDidImportIsTrue() {
var model = DataImportViewModel()
let model = DataImportViewModel()
model.successfulImportHappened = true

XCTAssertTrue(provider.didImport)
4 changes: 2 additions & 2 deletions UnitTests/Preferences/AppearancePreferencesTests.swift
Original file line number Diff line number Diff line change
@@ -175,8 +175,8 @@ final class AppearancePreferencesTests: XCTestCase {

func testPersisterReturnsValuesFromDisk() {
UserDefaultsWrapper<Any>.clearAll()
var persister1 = AppearancePreferencesUserDefaultsPersistor()
var persister2 = AppearancePreferencesUserDefaultsPersistor()
let persister1 = AppearancePreferencesUserDefaultsPersistor()
let persister2 = AppearancePreferencesUserDefaultsPersistor()

persister2.isFavoriteVisible = false
persister1.isFavoriteVisible = true
4 changes: 2 additions & 2 deletions UnitTests/Preferences/DuckPlayerPreferencesTests.swift
Original file line number Diff line number Diff line change
@@ -72,8 +72,8 @@ final class DuckPlayerPreferencesTests: XCTestCase {

func testPersisterReturnsValuesFromDisk() {
UserDefaultsWrapper<Any>.clearAll()
var persister1 = DuckPlayerPreferencesUserDefaultsPersistor()
var persister2 = DuckPlayerPreferencesUserDefaultsPersistor()
let persister1 = DuckPlayerPreferencesUserDefaultsPersistor()
let persister2 = DuckPlayerPreferencesUserDefaultsPersistor()

persister2.duckPlayerModeBool = nil
persister1.duckPlayerModeBool = true
2 changes: 1 addition & 1 deletion UnitTests/Statistics/CBRCompileTimeReporterTests.swift
Original file line number Diff line number Diff line change
@@ -40,7 +40,7 @@ class CBRCompileTimeReporterTests: XCTestCase {
}

func initReporter(onboardingFinished: Bool) -> Reporter {
var udWrapper = UserDefaultsWrapper(key: .onboardingFinished, defaultValue: true)
let udWrapper = UserDefaultsWrapper(key: .onboardingFinished, defaultValue: true)
udWrapper.wrappedValue = onboardingFinished

let reporter = Reporter()
2 changes: 1 addition & 1 deletion UnitTests/Statistics/LocalStatisticsStoreTests.swift
Original file line number Diff line number Diff line change
@@ -66,7 +66,7 @@ class LocalStatisticsStoreTests: XCTestCase {
// Legacy Statistics:

func testWhenInitializingTheLocalStatisticsStore_ThenLegacyStatisticsAreCleared() {
var legacyStore = LocalStatisticsStore.LegacyStatisticsStore()
let legacyStore = LocalStatisticsStore.LegacyStatisticsStore()
legacyStore.atb = "atb"

XCTAssertNotNil(legacyStore.atb)
13 changes: 12 additions & 1 deletion UnitTests/Tab/WKWebViewPrivateMethodsAvailabilityTests.swift
Original file line number Diff line number Diff line change
@@ -16,8 +16,9 @@
// limitations under the License.
//

import XCTest
import Navigation
import WebKit
import XCTest
@testable import DuckDuckGo_Privacy_Browser

final class WKWebViewPrivateMethodsAvailabilityTests: XCTestCase {
@@ -34,4 +35,14 @@ final class WKWebViewPrivateMethodsAvailabilityTests: XCTestCase {
XCTAssertTrue(WKBackForwardList.instancesRespond(to: WKBackForwardList.removeAllItemsSelector))
}

func testWKWebpagePreferencesCustomHeaderFieldsSupported() {
XCTAssertTrue(NavigationPreferences.customHeadersSupported)
let testHeaders = ["X-CUSTOM-HEADER": "TEST"]
let customHeaderFields = CustomHeaderFields(fields: testHeaders, thirdPartyDomains: [URL.duckDuckGo.host!])
XCTAssertNotNil(customHeaderFields as? NSObject)
let pagePrefs = WKWebpagePreferences()
pagePrefs.customHeaderFields = customHeaderFields.map { [$0] }
XCTAssertEqual(pagePrefs.customHeaderFields, customHeaderFields.map { [$0] })
}

}
Original file line number Diff line number Diff line change
@@ -19,9 +19,9 @@
import Navigation
import WebKit
import XCTest

@testable import DuckDuckGo_Privacy_Browser

@available(macOS 12.0, *)
class SerpHeadersNavigationResponderTests: XCTestCase {

let ddgUrls = [
@@ -49,46 +49,56 @@ class SerpHeadersNavigationResponderTests: XCTestCase {
contentBlockingMock.privacyConfigurationManager.privacyConfig as! MockPrivacyConfiguration
}

var webViewConfiguration: WKWebViewConfiguration!
var schemeHandler: TestSchemeHandler!

override func setUp() {
contentBlockingMock = ContentBlockingMock()
privacyFeaturesMock = AppPrivacyFeatures(contentBlocking: contentBlockingMock, httpsUpgradeStore: HTTPSUpgradeStoreMock())
// disable waiting for CBR compilation on navigation
privacyConfiguration.isFeatureKeyEnabled = { _, _ in
return false
}

schemeHandler = TestSchemeHandler()
WKWebView.customHandlerSchemes = [.http, .https]
webViewConfiguration = WKWebViewConfiguration()
webViewConfiguration.setURLSchemeHandler(schemeHandler, forURLScheme: URL.NavigationalScheme.http.rawValue)
webViewConfiguration.setURLSchemeHandler(schemeHandler, forURLScheme: URL.NavigationalScheme.https.rawValue)
}

override func tearDown() {
contentBlockingMock = nil
privacyFeaturesMock = nil
schemeHandler = nil
WKWebView.customHandlerSchemes = []
}

// MARK: - Tests

@MainActor
func testOnDDGRequest_headersAdded() {
var onNavAction: (@MainActor (NavigationAction) -> NavigationActionPolicy?)!
let extensionsBuilder = TestTabExtensionsBuilder(load: []) { builder in { _, _ in
builder.add {
TestsClosureNavigationResponderTabExtension(.init { navigationAction, _ in
onNavAction(navigationAction)
})
}
}}
let tab = Tab(content: .none, privacyFeatures: privacyFeaturesMock, extensionsBuilder: extensionsBuilder, shouldLoadInBackground: true)

for url in ddgUrls {
let eNavAction = expectation(description: "onNavAction for \(url.absoluteString)")
onNavAction = { navigationAction in
XCTAssertEqual(navigationAction.url, url)
for (key, value) in SerpHeadersNavigationResponder.headers {
XCTAssertEqual(navigationAction.request.value(forHTTPHeaderField: key), value, "for " + url.absoluteString)
let eRequestReceived = expectation(description: "Request received for \(url.absoluteString)")
let eDidFinish = expectation(description: "Navigation did finish for \(url.absoluteString)")
let extensionsBuilder = TestTabExtensionsBuilder(load: []) { builder in { _, _ in
builder.add {
TestsClosureNavigationResponderTabExtension(.init(navigationDidFinish: { _ in
eDidFinish.fulfill()
}))
}
}}
let tab = Tab(content: .none, webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock, extensionsBuilder: extensionsBuilder, shouldLoadInBackground: true)

eNavAction.fulfill()
schemeHandler.middleware = [{ request in
XCTAssertEqual(request.url, url)
for (key, value) in SerpHeadersNavigationResponder.headers {
XCTAssertEqual(request.value(forHTTPHeaderField: key), value, "for " + url.absoluteString)
}

return .cancel
}
eRequestReceived.fulfill()
return .ok(.html(""))
}]

tab.setContent(.url(url, source: .link))
waitForExpectations(timeout: 5)
@@ -98,29 +108,27 @@ class SerpHeadersNavigationResponderTests: XCTestCase {

@MainActor
func testOnRegularRequest_headersNotAdded() {
var onNavAction: (@MainActor (NavigationAction) -> NavigationActionPolicy?)!
let extensionsBuilder = TestTabExtensionsBuilder(load: []) { builder in { _, _ in
builder.add {
TestsClosureNavigationResponderTabExtension(.init { navigationAction, _ in
onNavAction(navigationAction)
})
}
}}

let tab = Tab(content: .none, privacyFeatures: privacyFeaturesMock, extensionsBuilder: extensionsBuilder, shouldLoadInBackground: true)

for url in nonDdgUrls {
let eNavAction = expectation(description: "onNavAction for \(url.absoluteString)")
onNavAction = { navigationAction in
XCTAssertEqual(navigationAction.url, url)
for (key, _) in SerpHeadersNavigationResponder.headers {
XCTAssertNil(navigationAction.request.value(forHTTPHeaderField: key), "for " + url.absoluteString)
let eRequestReceived = expectation(description: "Request received for \(url.absoluteString)")
let eDidFinish = expectation(description: "Navigation did finish for \(url.absoluteString)")
let extensionsBuilder = TestTabExtensionsBuilder(load: []) { builder in { _, _ in
builder.add {
TestsClosureNavigationResponderTabExtension(.init(navigationDidFinish: { _ in
eDidFinish.fulfill()
}))
}
}}
let tab = Tab(content: .none, webViewConfiguration: webViewConfiguration, privacyFeatures: privacyFeaturesMock, extensionsBuilder: extensionsBuilder, shouldLoadInBackground: true)

eNavAction.fulfill()
schemeHandler.middleware = [{ request in
XCTAssertEqual(request.url, url)
for (key, _) in SerpHeadersNavigationResponder.headers {
XCTAssertNil(request.value(forHTTPHeaderField: key), "for " + url.absoluteString)
}

return .cancel
}
eRequestReceived.fulfill()
return .ok(.html(""))
}]

tab.setContent(.url(url, source: .link))
waitForExpectations(timeout: 5)

0 comments on commit 23e491d

Please sign in to comment.