Skip to content

Commit

Permalink
Merge release/1.122.0 into main
Browse files Browse the repository at this point in the history
  • Loading branch information
daxmobile authored Jan 17, 2025
2 parents f105100 + b57bbd6 commit ae3a141
Show file tree
Hide file tree
Showing 16 changed files with 171 additions and 31 deletions.
2 changes: 1 addition & 1 deletion Configuration/BuildNumber.xcconfig
Original file line number Diff line number Diff line change
@@ -1 +1 @@
CURRENT_PROJECT_VERSION = 344
CURRENT_PROJECT_VERSION = 345
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ final class NetworkProtectionNavBarPopoverManager: NetPPopoverManager {
activeSitePublisher: activeSitePublisher,
forMenuApp: false,
vpnSettings: vpnSettings,
proxySettings: proxySettings,
logger: Logger(subsystem: "DuckDuckGo", category: "TipKit"))

let popover = NetworkProtectionPopover(
Expand Down
10 changes: 7 additions & 3 deletions DuckDuckGo/Preferences/Model/VPNPreferencesModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import Combine
import Foundation
import NetworkProtection
import NetworkProtectionIPC
import NetworkProtectionProxy
import NetworkProtectionUI
import BrowserServicesKit

Expand Down Expand Up @@ -77,8 +78,9 @@ final class VPNPreferencesModel: ObservableObject {
///
/// Only necessary because this is feature flagged to internal users.
///
@Published
var showExcludedSites: Bool
var showExcludedSites: Bool {
proxySettings.proxyAvailable
}

@Published var notifyStatusChanges: Bool {
didSet {
Expand All @@ -100,16 +102,19 @@ final class VPNPreferencesModel: ObservableObject {

private let vpnXPCClient: VPNControllerXPCClient
private let settings: VPNSettings
private let proxySettings: TransparentProxySettings
private let pinningManager: PinningManager
private var cancellables = Set<AnyCancellable>()

init(vpnXPCClient: VPNControllerXPCClient = .shared,
settings: VPNSettings = .init(defaults: .netP),
proxySettings: TransparentProxySettings = .init(defaults: .netP),
pinningManager: PinningManager = LocalPinningManager.shared,
defaults: UserDefaults = .netP) {

self.vpnXPCClient = vpnXPCClient
self.settings = settings
self.proxySettings = proxySettings
self.pinningManager = pinningManager

connectOnLogin = settings.connectOnLogin
Expand All @@ -118,7 +123,6 @@ final class VPNPreferencesModel: ObservableObject {
showInMenuBar = settings.showInMenuBar
showInBrowserToolbar = pinningManager.isPinned(.networkProtection)
showUninstallVPN = defaults.networkProtectionOnboardingStatus != .default
showExcludedSites = true
onboardingStatus = defaults.networkProtectionOnboardingStatus
locationItem = VPNLocationPreferenceItemModel(selectedLocation: settings.selectedLocation)

Expand Down
12 changes: 11 additions & 1 deletion DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,17 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate {

private let tunnelSettings: VPNSettings
private lazy var userDefaults = UserDefaults.netP
private lazy var proxySettings = TransparentProxySettings(defaults: .netP)
private lazy var proxySettings: TransparentProxySettings = {
let settings = TransparentProxySettings(defaults: .netP)

#if APPSTORE
settings.proxyAvailable = false
#else
settings.proxyAvailable = true
#endif

return settings
}()

@MainActor
private lazy var vpnProxyLauncher = VPNProxyLauncher(
Expand Down
1 change: 1 addition & 0 deletions LocalPackages/NetworkProtectionMac/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ let package = Package(
name: "NetworkProtectionUI",
dependencies: [
"VPNPixels",
"NetworkProtectionProxy",
.product(name: "NetworkProtection", package: "BrowserServicesKit"),
.product(name: "PixelKit", package: "BrowserServicesKit"),
.product(name: "SwiftUIExtensions", package: "SwiftUIExtensions"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,8 @@ public final class TransparentProxyController {
// MARK: - Start & stop the proxy

public var isRequiredForActiveFeatures: Bool {
settings.appRoutingRules.count > 0 || settings.excludedDomains.count > 0
settings.proxyAvailable
&& (settings.appRoutingRules.count > 0 || settings.excludedDomains.count > 0)
}

public func start() async throws {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ final class TransparentProxyAppMessageHandler {
settings.appRoutingRules = routingRules
case .excludedDomains(let excludedDomains):
settings.excludedDomains = excludedDomains
case .proxyAvailable(let available):
settings.proxyAvailable = available
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ open class TransparentProxyProvider: NETransparentProxyProvider {
Task {
try await self.updateNetworkSettings()
}
case .proxyAvailable:
// no-op, handled by app
break
}
}.store(in: &cancellables)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public final class TransparentProxySettings {
public enum Change: Codable {
case appRoutingRules(_ routingRules: VPNAppRoutingRules)
case excludedDomains(_ excludedDomains: [String])
case proxyAvailable(_ available: Bool)
}

let defaults: UserDefaults
Expand All @@ -35,6 +36,12 @@ public final class TransparentProxySettings {
.map { routingRules in
Change.appRoutingRules(routingRules)
}.eraseToAnyPublisher(),
defaults.vpnProxyFeatureAvailablePublisher
.dropFirst()
.removeDuplicates()
.map { available in
Change.proxyAvailable(available)
}.eraseToAnyPublisher(),
defaults.vpnProxyExcludedDomainsPublisher
.dropFirst()
.removeDuplicates()
Expand Down Expand Up @@ -70,6 +77,16 @@ public final class TransparentProxySettings {
}
}

public var proxyAvailable: Bool {
get {
defaults.vpnProxyFeatureAvailable
}

set {
defaults.vpnProxyFeatureAvailable = newValue
}
}

// MARK: - Reset to factory defaults

public func resetAll() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// UserDefaults+vpnProxyFeatureAvailable.swift
//
// Copyright © 2024 DuckDuckGo. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import Combine
import Foundation

extension UserDefaults {
@objc
dynamic var vpnProxyFeatureAvailable: Bool {
get {
bool(forKey: #keyPath(vpnProxyFeatureAvailable))
}

set {
set(newValue, forKey: #keyPath(vpnProxyFeatureAvailable))
}
}

var vpnProxyFeatureAvailablePublisher: AnyPublisher<Bool, Never> {
publisher(for: \.vpnProxyFeatureAvailable).eraseToAnyPublisher()
}

func resetVPNProxyFeatureAvailable() {
removeObject(forKey: #keyPath(vpnProxyFeatureAvailable))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import Combine
import Common
import LoginItems
import NetworkProtection
import NetworkProtectionProxy
import os.log
import SwiftUI

Expand Down Expand Up @@ -159,6 +160,7 @@ public final class StatusBarMenu: NSObject {
activeSitePublisher: activeSitePublisher,
forMenuApp: true,
vpnSettings: VPNSettings(defaults: userDefaults),
proxySettings: TransparentProxySettings(defaults: userDefaults),
logger: Logger(subsystem: "DuckDuckGo", category: "TipKit"))

let debugInformationViewModel = DebugInformationViewModel(showDebugInformation: isOptionKeyPressed)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ extension NetworkProtectionStatusView {
onboardingStatusPublisher: onboardingStatusPublisher,
statusReporter: statusReporter,
vpnSettings: .init(defaults: userDefaults),
proxySettings: .init(defaults: userDefaults),
locationFormatter: locationFormatter,
uiActionHandler: uiActionHandler)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import AppKit
import Combine
import Common
import NetworkProtection
import NetworkProtectionProxy
import os.log
import TipKit
import PixelKit
Expand Down Expand Up @@ -57,6 +58,7 @@ public final class VPNTipsModel: ObservableObject {

private let isMenuApp: Bool
private let vpnSettings: VPNSettings
private let proxySettings: TransparentProxySettings
private let logger: Logger
private var cancellables = Set<AnyCancellable>()

Expand All @@ -65,6 +67,7 @@ public final class VPNTipsModel: ObservableObject {
activeSitePublisher: CurrentValuePublisher<ActiveSiteInfo?, Never>,
forMenuApp isMenuApp: Bool,
vpnSettings: VPNSettings,
proxySettings: TransparentProxySettings,
logger: Logger) {

self.activeSiteInfo = activeSitePublisher.value
Expand All @@ -73,6 +76,7 @@ public final class VPNTipsModel: ObservableObject {
self.isMenuApp = isMenuApp
self.logger = logger
self.vpnSettings = vpnSettings
self.proxySettings = proxySettings

guard !isMenuApp else {
return
Expand Down Expand Up @@ -135,6 +139,44 @@ public final class VPNTipsModel: ObservableObject {

var geoswitchingStatusUpdateTask: Task<Void, Never>?

@available(macOS 14.0, *)
var canShowDomainExclusionsTip: Bool {
guard canShowTips else {
return false
}

// If the proxy is available, we can show this tip after the geoswitchin tip
// Otherwise we can't show this tip
if proxySettings.proxyAvailable,
case .invalidated = geoswitchingTip.status {

return true
}

return false
}

@available(macOS 14.0, *)
var canShowAutoconnectTip: Bool {
guard canShowTips else {
return false
}

// If the proxy is available, we need to wait until the domain exclusions tip was shown.
// If the proxy is not available, we can show this tip after the geoswitchin tip
if proxySettings.proxyAvailable,
case .invalidated = domainExclusionsTip.status {

return true
} else if !proxySettings.proxyAvailable,
case .invalidated = geoswitchingTip.status {

return true
}

return false
}

// MARK: - Tip Action handling

@available(macOS 14.0, *)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,7 @@ public struct TunnelControllerView: View {
featureToggleRow()

if #available(macOS 14.0, *),
tipsModel.canShowTips,
case .invalidated = tipsModel.domainExclusionsTip.status {
tipsModel.canShowAutoconnectTip {

TipView(tipsModel.autoconnectTip, action: tipsModel.autoconnectTipActionHandler)
.tipImageSize(VPNTipsModel.imageSize)
Expand All @@ -82,34 +81,35 @@ public struct TunnelControllerView: View {
}
}

SiteTroubleshootingView()
.padding(.top, 5)
if model.exclusionsFeatureEnabled {
SiteTroubleshootingView()
.padding(.top, 5)

if #available(macOS 14.0, *),
tipsModel.canShowTips,
case .invalidated = tipsModel.geoswitchingTip.status {

TipView(tipsModel.domainExclusionsTip)
.tipImageSize(VPNTipsModel.imageSize)
.tipBackground(Color(.tipBackground))
.padding(.horizontal, 9)
.padding(.vertical, 6)
.onAppear {
tipsModel.handleDomainExclusionsTipShown()
}
.task {
var previousStatus = tipsModel.domainExclusionsTip.status
if #available(macOS 14.0, *),
tipsModel.canShowDomainExclusionsTip {

for await status in tipsModel.domainExclusionsTip.statusUpdates {
if case .invalidated(let reason) = status {
if case .available = previousStatus {
tipsModel.handleDomainExclusionTipInvalidated(reason)
TipView(tipsModel.domainExclusionsTip)
.tipImageSize(VPNTipsModel.imageSize)
.tipBackground(Color(.tipBackground))
.padding(.horizontal, 9)
.padding(.vertical, 6)
.onAppear {
tipsModel.handleDomainExclusionsTipShown()
}
.task {
var previousStatus = tipsModel.domainExclusionsTip.status

for await status in tipsModel.domainExclusionsTip.statusUpdates {
if case .invalidated(let reason) = status {
if case .available = previousStatus {
tipsModel.handleDomainExclusionTipInvalidated(reason)
}
}
}

previousStatus = status
previousStatus = status
}
}
}
}
}

Divider()
Expand Down
Loading

0 comments on commit ae3a141

Please sign in to comment.