Skip to content

Commit

Permalink
Merge branch 'main' into dominik/xcode-16
Browse files Browse the repository at this point in the history
* main:
  Use cookie to share subscription access token on DDG domains (#1034)
  update css dependency (#1037)
  Email parsing improved (#1016)
  Add NTP Search Bar feature flag (#1023)
  VPN logs fix (#1030)
  Add AI Chat feature flag (#1031)
  fix breakByRaisingSigInt mistakenly called when run w/o debugger (#1029)
  • Loading branch information
samsymons committed Oct 28, 2024
2 parents 748463e + e5946ee commit ac3faeb
Show file tree
Hide file tree
Showing 23 changed files with 665 additions and 79 deletions.
4 changes: 2 additions & 2 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/duckduckgo/content-scope-scripts",
"state" : {
"revision" : "1ed569676555d493c9c5575eaed22aa02569aac9",
"version" : "6.19.0"
"revision" : "b74549bd869fdecc16fad851f2f608b1724764df",
"version" : "6.25.0"
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ let package = Package(
.package(url: "https://github.com/duckduckgo/sync_crypto", exact: "0.2.0"),
.package(url: "https://github.com/gumob/PunycodeSwift.git", exact: "3.0.0"),
.package(url: "https://github.com/duckduckgo/privacy-dashboard", exact: "5.3.0"),
.package(url: "https://github.com/duckduckgo/content-scope-scripts", exact: "6.19.0"),
.package(url: "https://github.com/duckduckgo/content-scope-scripts", exact: "6.25.0"),
.package(url: "https://github.com/httpswift/swifter.git", exact: "1.5.0"),
.package(url: "https://github.com/duckduckgo/bloom_cpp.git", exact: "3.0.0"),
.package(url: "https://github.com/1024jp/GzipSwift.git", exact: "6.0.1")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public enum PrivacyFeature: String {
case windowsDownloadLink
case incontextSignup
case newTabContinueSetUp
case newTabSearchField
case dbp
case sync
case privacyDashboard
Expand All @@ -60,6 +61,8 @@ public enum PrivacyFeature: String {
case marketplaceAdPostback
case autocompleteTabs
case networkProtection
case aiChat
case contextualOnboarding
}

/// An abstraction to be implemented by any "subfeature" of a given `PrivacyConfiguration` feature.
Expand Down Expand Up @@ -97,6 +100,18 @@ public enum DBPSubfeature: String, Equatable, PrivacySubfeature {
case freemium
}

public enum AIChatSubfeature: String, Equatable, PrivacySubfeature {
public var parent: PrivacyFeature {
.aiChat
}

/// Displays the settings item for showing a shortcut in the Application Menu
case applicationMenuShortcut

/// Displays the settings item for showing a shortcut in the Toolbar
case toolbarShortcut
}

public enum NetworkProtectionSubfeature: String, Equatable, PrivacySubfeature {
public var parent: PrivacyFeature {
.networkProtection
Expand Down
8 changes: 3 additions & 5 deletions Sources/Common/Debug.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,11 @@ public func breakByRaisingSigInt(_ description: String, file: StaticString = #fi
#if DEBUG

// get symbol from stack trace for a caller of a calling method
public func callingSymbol() -> String {
public func callingSymbol(after lastSymbolName: String? = nil) -> String {
let stackTrace = Thread.callStackSymbols
// find `callingSymbol` itself or dispatch_once_callout
var callingSymbolIdx = stackTrace.firstIndex(where: { $0.contains("_dispatch_once_callout") })
?? stackTrace.firstIndex(where: { $0.contains("callingSymbol") })!
// procedure calling `callingSymbol`
callingSymbolIdx += 1
var callingSymbolIdx = lastSymbolName.flatMap { lastSymbolName in stackTrace.lastIndex(where: { $0.contains(lastSymbolName) }) }
?? stackTrace.firstIndex(where: { $0.contains("callingSymbol") })! + 1 // procedure calling `callingSymbol`

var symbolName: String
repeat {
Expand Down
24 changes: 23 additions & 1 deletion Sources/Common/Extensions/URLExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ extension URL {
return true
}

// swiftlint:disable cyclomatic_complexity
/// URL and URLComponents can't cope with emojis and international characters so this routine does some manual processing while trying to
/// retain the input as much as possible.
public init?(trimmedAddressBarString: String) {
Expand Down Expand Up @@ -176,7 +177,23 @@ extension URL {
urlWithScheme.port != nil || urlWithScheme.user != nil {
// could be a local domain but user needs to use the protocol to specify that
// make exception for "localhost"
guard urlWithScheme.host?.contains(".") == true || urlWithScheme.host == .localhost else { return nil }
let hasDomain = urlWithScheme.host?.contains(".") == true
guard hasDomain || urlWithScheme.host == .localhost else { return nil }

let isInvalidUserInfo = {
let hasUser = urlWithScheme.user != nil
let hasPassword = urlWithScheme.password != nil
let hasPath = !urlWithScheme.path.isEmpty
let hasPort = urlWithScheme.port != nil
let hasFragment = urlWithScheme.fragment != nil

return hasUser && !hasPassword && !hasPath && !hasPort && !hasFragment
}()

if isInvalidUserInfo {
return nil
}

self = urlWithScheme
return

Expand Down Expand Up @@ -204,6 +221,7 @@ extension URL {

self.init(punycodeEncodedString: s)
}
// swiftlint:enable cyclomatic_complexity

private init?(punycodeEncodedString: String) {
var s = punycodeEncodedString
Expand All @@ -223,6 +241,10 @@ extension URL {

guard let (authData, urlPart, query) = Self.fixupAndSplitURLString(s) else { return nil }

if (authData?.contains(" ") == true) || urlPart.contains(" ") {
return nil
}

let componentsWithoutQuery = urlPart.split(separator: "/").map(String.init)
guard !componentsWithoutQuery.isEmpty else {
return nil
Expand Down
3 changes: 2 additions & 1 deletion Sources/Navigation/Extensions/WKFrameInfoExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ public extension WKFrameInfo {
method_exchangeImplementations(originalRequestMethod, swizzledRequestMethod)

// ignore `request` selector calls from `safeRequest` itself
ignoredRequestUsageSymbols.insert(callingSymbol())
let callingSymbol = callingSymbol(after: "addSafetyCheckForSafeRequestUsageOnce")
ignoredRequestUsageSymbols.insert(callingSymbol)
// ignore `-[WKFrameInfo description]`
ignoredRequestUsageSymbols.insert("-[WKFrameInfo description]")
}()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,9 @@ extension WKNavigationAction: WebViewNavigationAction {
let swizzledSourceFrameMethod = class_getInstanceMethod(WKNavigationAction.self, #selector(WKNavigationAction.swizzledSourceFrame))!
method_exchangeImplementations(originalSourceFrameMethod, swizzledSourceFrameMethod)

let callingSymbol = callingSymbol(after: "addSafetyCheckForSafeSourceFrameUsageOnce")
// ignore `sourceFrame` selector calls from `safeSourceFrame` itself
ignoredSourceFrameUsageSymbols.insert(callingSymbol())
ignoredSourceFrameUsageSymbols.insert(callingSymbol)
// ignore `-[WKNavigationAction description]`
ignoredSourceFrameUsageSymbols.insert("-[WKNavigationAction description]")
}()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,18 @@ public actor NetworkProtectionServerStatusMonitor {
// MARK: - Start/Stop monitoring

public func start(serverName: String, callback: @escaping (ServerStatusResult) -> Void) {
Logger.networkProtectionServerStatusMonitor.debug("⚫️ Starting server status monitor for \(serverName, privacy: .public)")
Logger.networkProtectionServerStatusMonitor.log("⚫️ Starting server status monitor for \(serverName, privacy: .public)")

task = Task.periodic(delay: Self.monitoringInterval, interval: Self.monitoringInterval) {
let result = await self.checkServerStatus(for: serverName)

switch result {
case .success(let serverStatus):
if serverStatus.shouldMigrate {
Logger.networkProtectionMemory.debug("⚫️ Initiating server migration away from \(serverName, privacy: .public)")
Logger.networkProtectionMemory.log("⚫️ Initiating server migration away from \(serverName, privacy: .public)")
callback(.serverMigrationRequested)
} else {
Logger.networkProtectionMemory.debug("⚫️ No migration requested for \(serverName, privacy: .public)")
Logger.networkProtectionMemory.log("⚫️ No migration requested for \(serverName, privacy: .public)")
}
case .failure(let error):
Logger.networkProtectionMemory.error("⚫️ Error retrieving server status: \(error.localizedDescription, privacy: .public)")
Expand All @@ -90,7 +90,7 @@ public actor NetworkProtectionServerStatusMonitor {
}

public func stop() {
Logger.networkProtectionMemory.error("⚫️ Stopping server status monitor")
Logger.networkProtectionMemory.log("⚫️ Stopping server status monitor")

task?.cancel()
task = nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public actor NetworkProtectionTunnelFailureMonitor {
// MARK: - Start/Stop monitoring

func start(callback: @escaping (Result) -> Void) {
Logger.networkProtectionTunnelFailureMonitor.debug("⚫️ Starting tunnel failure monitor")
Logger.networkProtectionTunnelFailureMonitor.log("⚫️ Starting tunnel failure monitor")

failureReported = false
firstCheckSkipped = false
Expand All @@ -93,7 +93,7 @@ public actor NetworkProtectionTunnelFailureMonitor {
}

func stop() {
Logger.networkProtectionTunnelFailureMonitor.debug("⚫️ Stopping tunnel failure monitor")
Logger.networkProtectionTunnelFailureMonitor.log("⚫️ Stopping tunnel failure monitor")

networkMonitor.cancel()
networkMonitor.pathUpdateHandler = nil
Expand All @@ -108,31 +108,31 @@ public actor NetworkProtectionTunnelFailureMonitor {
guard firstCheckSkipped else {
// Avoid running the first tunnel failure check after startup to avoid reading the first handshake after sleep, which will almost always
// be out of date. In normal operation, the first check will frequently be 0 as WireGuard hasn't had the chance to handshake yet.
Logger.networkProtectionTunnelFailureMonitor.debug("⚫️ Skipping first tunnel failure check")
Logger.networkProtectionTunnelFailureMonitor.log("⚫️ Skipping first tunnel failure check")
firstCheckSkipped = true
return
}

let mostRecentHandshake = (try? await handshakeReporter.getMostRecentHandshake()) ?? 0

guard mostRecentHandshake > 0 else {
Logger.networkProtectionTunnelFailureMonitor.debug("⚫️ Got handshake timestamp at or below 0, skipping check")
Logger.networkProtectionTunnelFailureMonitor.log("⚫️ Got handshake timestamp at or below 0, skipping check")
return
}

let difference = Date().timeIntervalSince1970 - mostRecentHandshake
Logger.networkProtectionTunnelFailureMonitor.debug("⚫️ Last handshake: \(difference, privacy: .public) seconds ago")
Logger.networkProtectionTunnelFailureMonitor.log("⚫️ Last handshake: \(difference, privacy: .public) seconds ago")

if difference > Result.failureDetected.threshold, isConnected {
if failureReported {
Logger.networkProtectionTunnelFailureMonitor.debug("⚫️ Tunnel failure already reported")
Logger.networkProtectionTunnelFailureMonitor.log("⚫️ Tunnel failure already reported")
} else {
Logger.networkProtectionTunnelFailureMonitor.debug("⚫️ Tunnel failure reported")
Logger.networkProtectionTunnelFailureMonitor.log("⚫️ Tunnel failure reported")
callback(.failureDetected)
failureReported = true
}
} else if difference <= Result.failureRecovered.threshold, failureReported {
Logger.networkProtectionTunnelFailureMonitor.debug("⚫️ Tunnel recovered from failure")
Logger.networkProtectionTunnelFailureMonitor.log("⚫️ Tunnel recovered from failure")
callback(.failureRecovered)
failureReported = false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,17 @@ public final class NetworkProtectionKeychainKeyStore: NetworkProtectionKeyStore
// MARK: - NetworkProtectionKeyStore

public func currentKeyPair() -> KeyPair? {
Logger.networkProtectionKeyManagement.debug("Querying the current key pair (publicKey: \(String(describing: self.currentPublicKey), privacy: .public), expirationDate: \(String(describing: self.currentExpirationDate), privacy: .public))")
Logger.networkProtectionKeyManagement.log("Querying the current key pair (publicKey: \(String(describing: self.currentPublicKey), privacy: .public), expirationDate: \(String(describing: self.currentExpirationDate), privacy: .public))")

guard let currentPrivateKey = currentPrivateKey else {
Logger.networkProtectionKeyManagement.debug("There's no current private key.")
Logger.networkProtectionKeyManagement.log("There's no current private key.")
return nil
}

guard let currentExpirationDate = currentExpirationDate,
Date().addingTimeInterval(validityInterval) >= currentExpirationDate else {

Logger.networkProtectionKeyManagement.debug("The expirationDate date is missing, or we're past it (now: \(String(describing: Date()), privacy: .public), expirationDate: \(String(describing: self.currentExpirationDate), privacy: .public))")
Logger.networkProtectionKeyManagement.log("The expirationDate date is missing, or we're past it (now: \(String(describing: Date()), privacy: .public), expirationDate: \(String(describing: self.currentExpirationDate), privacy: .public))")
return nil
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ public actor NetworkProtectionDeviceManager: NetworkProtectionDeviceManagement {
}

let (selectedServer, newExpiration) = try await register(keyPair: keyPair, selectionMethod: resolvedSelectionMethod)
Logger.networkProtection.debug("Server registration successul")
Logger.networkProtection.log("Server registration successul")

keyStore.updateKeyPair(keyPair)

Expand Down
4 changes: 2 additions & 2 deletions Sources/NetworkProtection/Networking/Pinger.swift
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ extension Pinger {
let seq = self.nextSeq()
sentIndices.insert(Int(seq))

Logger.networkProtection.debug("PING \(self.ip.debugDescription): \(MemoryLayout<ICMP>.size) data bytes")
Logger.networkProtection.log("PING \(self.ip.debugDescription): \(MemoryLayout<ICMP>.size) data bytes")
// form ICMP packet with id, icmp_seq, timestamp and checksum
let icmp = ICMP(id: id, index: seq)

Expand Down Expand Up @@ -352,7 +352,7 @@ extension Pinger {
return self.ip
}()
let r = PingResult(ip: srcIp, bytesCount: bytesCount, seq: Int(response.index), ttl: Int(ip.ip_ttl), time: end - icmp.timestamp)
Logger.networkProtection.debug("\(r.bytesCount) bytes from \(r.ip.debugDescription): icmp_seq=\(r.seq) ttl=\(r.ttl) time=\(r.time * 1000) ms")
Logger.networkProtection.log("\(r.bytesCount) bytes from \(r.ip.debugDescription): icmp_seq=\(r.seq) ttl=\(r.ttl) time=\(r.time * 1000) ms")

return .success(r)

Expand Down
Loading

0 comments on commit ac3faeb

Please sign in to comment.