Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Malicious site protection App settings #3734

Open
wants to merge 6 commits into
base: alessandro/malicious-site-protection-navigation-detection-integration
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Core/AppURLs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public extension URL {
static let apps = URL(string: AppDeepLinkSchemes.quickLink.appending("\(ddg.host!)/apps?origin=funnel_app_ios"))!
static let searchSettings = URL(string: AppDeepLinkSchemes.quickLink.appending("\(ddg.host!)/settings"))!
static let autofillHelpPageLink = URL(string: AppDeepLinkSchemes.quickLink.appending("\(ddg.host!)/duckduckgo-help-pages/sync-and-backup/password-manager-security/"))!
static let maliciousSiteProtectionLearnMore = URL(string: AppDeepLinkSchemes.quickLink.appending("\(ddg.host!)/duckduckgo-help-pages/privacy/phishing-and-malware-protection/"))!

static let surrogates = URL(string: "\(staticBase)/surrogates.txt")!

Expand Down
3 changes: 3 additions & 0 deletions Core/UserDefaultsPropertyWrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,9 @@ public struct UserDefaultsWrapper<T> {

// TipKit
case resetTipKitOnNextLaunch = "com.duckduckgo.ios.tipKit.resetOnNextLaunch"

// Malicious Site Protection
case maliciousSiteProtectionEnabled = "com.duckduckgo.ios.maliciousSiteProtection.enabled"
}

private let key: Key
Expand Down
26 changes: 25 additions & 1 deletion DuckDuckGo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,9 @@
9F06EB7D2D0AEBD000905426 /* MaliciousSiteProtectionManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F06EB7C2D0AEBD000905426 /* MaliciousSiteProtectionManagerTests.swift */; };
9F06EB822D0AEE1F00905426 /* MaliciousSiteProtectionMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F06EB802D0AEE1F00905426 /* MaliciousSiteProtectionMocks.swift */; };
9F06EB872D0C733B00905426 /* MaliciousSiteProtectionPreferencesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F06EB862D0C733900905426 /* MaliciousSiteProtectionPreferencesManager.swift */; };
9F06EB8A2D10560200905426 /* SettingsMaliciousSiteProtectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F06EB892D10560200905426 /* SettingsMaliciousSiteProtectionView.swift */; };
9F06EB8C2D10578000905426 /* MaliciousSiteProtectionSettingsViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F06EB8B2D10578000905426 /* MaliciousSiteProtectionSettingsViewModelTests.swift */; };
9F06EB922D10740500905426 /* MaliciousSiteProtectionPreferencesManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F06EB912D10740500905426 /* MaliciousSiteProtectionPreferencesManagerTests.swift */; };
9F16230B2CA0F0190093C4FC /* DebouncerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F16230A2CA0F0190093C4FC /* DebouncerTests.swift */; };
9F1798572CD2443F0073018B /* AddToDockPromoViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F1798562CD2443F0073018B /* AddToDockPromoViewModelTests.swift */; };
9F23B8012C2BC94400950875 /* OnboardingBackground.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F23B8002C2BC94400950875 /* OnboardingBackground.swift */; };
Expand Down Expand Up @@ -820,6 +823,7 @@
9F9A92342C86B42B001D036D /* AppIconPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F9A92332C86B42B001D036D /* AppIconPicker.swift */; };
9F9EE4CE2C377D4900D4118E /* OnboardingFirePixelMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F9EE4CC2C377D3F00D4118E /* OnboardingFirePixelMock.swift */; };
9F9EE4D42C37BB1300D4118E /* OnboardingView+Landing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F9EE4D32C37BB1300D4118E /* OnboardingView+Landing.swift */; };
9F9F325A2CEFA75100211B49 /* MaliciousSiteProtectionSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F9F32592CEFA74600211B49 /* MaliciousSiteProtectionSettingsViewModel.swift */; };
9FA5E44B2BF1AF3400BDEF02 /* SubscriptionContainerViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA5E44A2BF1AF3400BDEF02 /* SubscriptionContainerViewFactory.swift */; };
9FB027122C2526DD009EA190 /* OnboardingView+IntroDialogContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FB027112C2526DD009EA190 /* OnboardingView+IntroDialogContent.swift */; };
9FB027142C252E0C009EA190 /* OnboardingView+BrowsersComparisonContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FB027132C252E0C009EA190 /* OnboardingView+BrowsersComparisonContent.swift */; };
Expand Down Expand Up @@ -2633,6 +2637,9 @@
9F06EB7C2D0AEBD000905426 /* MaliciousSiteProtectionManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaliciousSiteProtectionManagerTests.swift; sourceTree = "<group>"; };
9F06EB802D0AEE1F00905426 /* MaliciousSiteProtectionMocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaliciousSiteProtectionMocks.swift; sourceTree = "<group>"; };
9F06EB862D0C733900905426 /* MaliciousSiteProtectionPreferencesManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaliciousSiteProtectionPreferencesManager.swift; sourceTree = "<group>"; };
9F06EB892D10560200905426 /* SettingsMaliciousSiteProtectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsMaliciousSiteProtectionView.swift; sourceTree = "<group>"; };
9F06EB8B2D10578000905426 /* MaliciousSiteProtectionSettingsViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaliciousSiteProtectionSettingsViewModelTests.swift; sourceTree = "<group>"; };
9F06EB912D10740500905426 /* MaliciousSiteProtectionPreferencesManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaliciousSiteProtectionPreferencesManagerTests.swift; sourceTree = "<group>"; };
9F16230A2CA0F0190093C4FC /* DebouncerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebouncerTests.swift; sourceTree = "<group>"; };
9F1798562CD2443F0073018B /* AddToDockPromoViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddToDockPromoViewModelTests.swift; sourceTree = "<group>"; };
9F23B8002C2BC94400950875 /* OnboardingBackground.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingBackground.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2698,6 +2705,7 @@
9F9A92332C86B42B001D036D /* AppIconPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIconPicker.swift; sourceTree = "<group>"; };
9F9EE4CC2C377D3F00D4118E /* OnboardingFirePixelMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingFirePixelMock.swift; sourceTree = "<group>"; };
9F9EE4D32C37BB1300D4118E /* OnboardingView+Landing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OnboardingView+Landing.swift"; sourceTree = "<group>"; };
9F9F32592CEFA74600211B49 /* MaliciousSiteProtectionSettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaliciousSiteProtectionSettingsViewModel.swift; sourceTree = "<group>"; };
9FA5E44A2BF1AF3400BDEF02 /* SubscriptionContainerViewFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionContainerViewFactory.swift; sourceTree = "<group>"; };
9FB027112C2526DD009EA190 /* OnboardingView+IntroDialogContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OnboardingView+IntroDialogContent.swift"; sourceTree = "<group>"; };
9FB027132C252E0C009EA190 /* OnboardingView+BrowsersComparisonContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OnboardingView+BrowsersComparisonContent.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3475,6 +3483,7 @@
1DEAADED2BA45DFE00E25A97 /* SettingsDataClearingView.swift */,
D65625A02C232F5E006EF297 /* SettingsDuckPlayerView.swift */,
317CA3422CFF82DB00F88848 /* SettingsAIChatView.swift */,
9F06EB892D10560200905426 /* SettingsMaliciousSiteProtectionView.swift */,
);
name = MainSettings;
sourceTree = "<group>";
Expand Down Expand Up @@ -5067,13 +5076,16 @@
9F06EB7F2D0AEE0600905426 /* Mocks */,
9F06EB792D09EC2000905426 /* MaliciousSiteProtectionFeatureFlagsTests.swift */,
9F06EB7C2D0AEBD000905426 /* MaliciousSiteProtectionManagerTests.swift */,
9F06EB8B2D10578000905426 /* MaliciousSiteProtectionSettingsViewModelTests.swift */,
9F06EB912D10740500905426 /* MaliciousSiteProtectionPreferencesManagerTests.swift */,
);
path = MaliciousSiteProtection;
sourceTree = "<group>";
};
9F06EB7F2D0AEE0600905426 /* Mocks */ = {
isa = PBXGroup;
children = (
9FBC76692CFE3802008B21E7 /* MockMaliciousSiteProtectionManager.swift */,
9F06EB802D0AEE1F00905426 /* MaliciousSiteProtectionMocks.swift */,
);
path = Mocks;
Expand All @@ -5087,6 +5099,14 @@
path = UserPreferences;
sourceTree = "<group>";
};
9F06EB882D0D737500905426 /* Settings */ = {
isa = PBXGroup;
children = (
9F9F32592CEFA74600211B49 /* MaliciousSiteProtectionSettingsViewModel.swift */,
);
path = Settings;
sourceTree = "<group>";
};
9F23B7FF2C2BABE000950875 /* OnboardingIntro */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -5141,6 +5161,7 @@
9F254AA92CF47CD30063B308 /* MaliciousSiteProtection */ = {
isa = PBXGroup;
children = (
9F06EB882D0D737500905426 /* Settings */,
9F06EB852D0C733100905426 /* UserPreferences */,
9F06EB742D09E8D200905426 /* FeatureFlags */,
9F254AF22CF8E1F30063B308 /* Resources */,
Expand Down Expand Up @@ -5171,7 +5192,6 @@
9F254AD72CF605310063B308 /* MockSSLErrorPageNavigationHandler.swift */,
9F254ADA2CF6120E0063B308 /* MockSpecialErrorPageNavigationDelegate.swift */,
9F254ADD2CF636CF0063B308 /* DummyWKNavigation.swift */,
9FBC76692CFE3802008B21E7 /* MockMaliciousSiteProtectionManager.swift */,
);
path = TestDoubles;
sourceTree = "<group>";
Expand Down Expand Up @@ -8223,6 +8243,7 @@
EEC02C142B0519DE0045CE11 /* NetworkProtectionVPNLocationViewModel.swift in Sources */,
D63FF8962C1B67E9006DE24D /* YoutubeOverlayUserScript.swift in Sources */,
9F38A28C2D09BDE500EB100E /* SpecialErrorPageThreatProvider.swift in Sources */,
9F9F325A2CEFA75100211B49 /* MaliciousSiteProtectionSettingsViewModel.swift in Sources */,
F13B4BC01F180D8A00814661 /* TabsModel.swift in Sources */,
8598D2E02CEB98B500C45685 /* Favicons.swift in Sources */,
8598D2E12CEB98B500C45685 /* NotFoundCachingDownloader.swift in Sources */,
Expand Down Expand Up @@ -8395,6 +8416,7 @@
9FCFCD852C75C91A006EB7A0 /* ProgressBarView.swift in Sources */,
6F3537A42C4AC140009F8717 /* NewTabPageDaxLogoView.swift in Sources */,
314C92B827C3DD660042EC96 /* QuickLookPreviewView.swift in Sources */,
9F06EB8A2D10560200905426 /* SettingsMaliciousSiteProtectionView.swift in Sources */,
6F5345AF2C53F2DE00424A43 /* NewTabPageSettingsPersistentStorage.swift in Sources */,
F1AE54E81F0425FC00D9A700 /* AuthenticationViewController.swift in Sources */,
560E990F2BEE2CB800507CE0 /* SyncErrorMessage.swift in Sources */,
Expand Down Expand Up @@ -8591,6 +8613,7 @@
987130C5294AAB9F00AB05E0 /* BookmarkEditorViewModelTests.swift in Sources */,
BDFF03262BA3DA4900F324C9 /* NetworkProtectionFeatureVisibilityTests.swift in Sources */,
9F8E0F332CCA642D001EA7C5 /* VideoPlayerViewModelTests.swift in Sources */,
9F06EB8C2D10578000905426 /* MaliciousSiteProtectionSettingsViewModelTests.swift in Sources */,
D62EC3BA2C246A7000FC9D04 /* YoutublePlayerNavigationHandlerTests.swift in Sources */,
1EAABE712C99FC75003F5137 /* SubscriptionFeatureAvailabilityMock.swift in Sources */,
8341D807212D5E8D000514C2 /* HashExtensionTest.swift in Sources */,
Expand Down Expand Up @@ -8698,6 +8721,7 @@
85E065C12C73ADDD00D73E2A /* UsageSegmentationStorageTests.swift in Sources */,
8536A1CA209AF6490050739E /* HomeRowReminderTests.swift in Sources */,
851DFD8A212C5EE800D95F20 /* TabSwitcherButtonTests.swift in Sources */,
9F06EB922D10740500905426 /* MaliciousSiteProtectionPreferencesManagerTests.swift in Sources */,
98983096255B5019003339A2 /* BookmarksCachingSearchTests.swift in Sources */,
D6B67A122C332B6E002122EB /* DuckPlayerMocks.swift in Sources */,
9FEA22352C327226006B03BF /* MockTimer.swift in Sources */,
Expand Down
2 changes: 2 additions & 0 deletions DuckDuckGo/AppDependencyProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ protocol DependencyProvider {
var serverInfoObserver: ConnectionServerInfoObserver { get }
var vpnSettings: VPNSettings { get }
var persistentPixel: PersistentPixelFiring { get }
var maliciousSiteProtectionPreferencesManager: MaliciousSiteProtectionPreferencesManaging { get }

}

Expand Down Expand Up @@ -91,6 +92,7 @@ final class AppDependencyProvider: DependencyProvider {
let serverInfoObserver: ConnectionServerInfoObserver = ConnectionServerInfoObserverThroughSession()
let vpnSettings = VPNSettings(defaults: .networkProtectionGroupDefaults)
let persistentPixel: PersistentPixelFiring = PersistentPixel()
let maliciousSiteProtectionPreferencesManager: MaliciousSiteProtectionPreferencesManaging = MaliciousSiteProtectionPreferencesManager()

private init() {
let featureFlaggerOverrides = FeatureFlagLocalOverrides(keyValueStore: UserDefaults(suiteName: FeatureFlag.localOverrideStoreName)!,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ final class MaliciousSiteProtectionManager: MaliciousSiteDetecting {
embeddedDataProvider: MaliciousSiteProtection.EmbeddedDataProviding = EmbeddedDataProvider(),
dataManager: MaliciousSiteProtection.DataManager? = nil,
detector: MaliciousSiteProtection.MaliciousSiteDetecting? = nil,
preferencesManager: MaliciousSiteProtectionPreferencesPublishing = MaliciousSiteProtectionPreferencesManager(),
preferencesManager: MaliciousSiteProtectionPreferencesPublishing = AppDependencyProvider.shared.maliciousSiteProtectionPreferencesManager,
maliciousSiteProtectionFeatureFlagger: MaliciousSiteProtectionFeatureFlagger = MaliciousSiteProtectionFeatureFlags(),
updateIntervalProvider: UpdateManager.UpdateIntervalProvider? = nil
) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//
// MaliciousSiteProtectionSettingsViewModel.swift
// DuckDuckGo
//
// 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 Foundation
import Combine
import Core
import SwiftUI

final class MaliciousSiteProtectionSettingsViewModel: ObservableObject {
@Published var shouldShowMaliciousSiteProtectionSection = false
@Published var isMaliciousSiteProtectionEnabled: Bool = false

var maliciousSiteProtectionBinding: Binding<Bool> {
Binding<Bool>(
get: {
self.manager.isEnabled
},
set: {
self.manager.isEnabled = $0
self.isMaliciousSiteProtectionEnabled = $0
}
)
}

private let manager: MaliciousSiteProtectionPreferencesManaging
private let featureFlagger: MaliciousSiteProtectionFeatureFlagger
private let urlOpener: URLOpener

init(
manager: MaliciousSiteProtectionPreferencesManaging = AppDependencyProvider.shared.maliciousSiteProtectionPreferencesManager,
featureFlagger: MaliciousSiteProtectionFeatureFlagger = MaliciousSiteProtectionFeatureFlags(),
urlOpener: URLOpener = UIApplication.shared
) {
self.manager = manager
self.featureFlagger = featureFlagger
self.urlOpener = urlOpener
shouldShowMaliciousSiteProtectionSection = featureFlagger.isMaliciousSiteProtectionEnabled
isMaliciousSiteProtectionEnabled = manager.isEnabled
}

func learnMoreAction() {
urlOpener.open(URL.maliciousSiteProtectionLearnMore)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,44 @@

import Foundation
import Combine
import Core

protocol MaliciousSiteProtectionPreferencesPublishing {
protocol MaliciousSiteProtectionPreferencesStorage: AnyObject {
var isEnabled: Bool { get set }
}

final class MaliciousSiteProtectionPreferencesUserDefaultsStore: MaliciousSiteProtectionPreferencesStorage {
@UserDefaultsWrapper(key: .maliciousSiteProtectionEnabled, defaultValue: false)
var isEnabled: Bool
}

protocol MaliciousSiteProtectionPreferencesReadable: AnyObject {
var isEnabled: Bool { get }
var isEnabledPublisher: AnyPublisher<Bool, Never> { get }
}

protocol MaliciousSiteProtectionPreferencesManaging {
protocol MaliciousSiteProtectionPreferencesWritable: AnyObject {
var isEnabled: Bool { get set }
}

final class MaliciousSiteProtectionPreferencesManager: MaliciousSiteProtectionPreferencesManaging, MaliciousSiteProtectionPreferencesPublishing {
@Published var isEnabled: Bool
protocol MaliciousSiteProtectionPreferencesPublishing: MaliciousSiteProtectionPreferencesReadable {
var isEnabledPublisher: AnyPublisher<Bool, Never> { get }
}

typealias MaliciousSiteProtectionPreferencesManaging = MaliciousSiteProtectionPreferencesWritable & MaliciousSiteProtectionPreferencesPublishing

final class MaliciousSiteProtectionPreferencesManager: MaliciousSiteProtectionPreferencesManaging {
@Published var isEnabled: Bool {
didSet {
store.isEnabled = isEnabled
}
}

var isEnabledPublisher: AnyPublisher<Bool, Never> { $isEnabled.eraseToAnyPublisher() }

init() {
isEnabled = true
private let store: MaliciousSiteProtectionPreferencesStorage

init(store: MaliciousSiteProtectionPreferencesStorage = MaliciousSiteProtectionPreferencesUserDefaultsStore()) {
self.store = store
isEnabled = store.isEnabled
}
}
3 changes: 3 additions & 0 deletions DuckDuckGo/SettingsGeneralView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ struct SettingsGeneralView: View {
SettingsCellView(label: UserText.settingsAssociatedApps,
accessory: .toggle(isOn: viewModel.universalLinksBinding))
}

SettingsMaliciousProtectionView()

}
.applySettingsListModifiers(title: UserText.general,
displayMode: .inline,
Expand Down
Loading
Loading