Skip to content
This repository was archived by the owner on Feb 24, 2025. It is now read-only.

Commit 0610231

Browse files
Malicious site protection feature flags (#3719)
Task/Issue URL: https://app.asana.com/0/72649045549333/1207944134334659/f Tech Design URL: https://app.asana.com/0/1206329551987282/1207273224076495/f **Description**: Add Feature flag class as per tech design to check if malicious site protection feature is enabled and should check protection for domain based on the domain privacy preferences.
1 parent 3448518 commit 0610231

File tree

7 files changed

+284
-14
lines changed

7 files changed

+284
-14
lines changed

Core/FeatureFlag.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ public enum FeatureFlag: String {
7171
case syncSeamlessAccountSwitching
7272

7373
case testExperiment
74+
75+
/// Feature flag to enable / disable phishing and malware protection
76+
/// https://app.asana.com/0/1206329551987282/1207149365636877/f
77+
case maliciousSiteProtection
7478
}
7579

7680
extension FeatureFlag: FeatureFlagDescribing {
@@ -174,6 +178,8 @@ extension FeatureFlag: FeatureFlagDescribing {
174178
return .remoteReleasable(.subfeature(SyncSubfeature.seamlessAccountSwitching))
175179
case .testExperiment:
176180
return .remoteReleasable(.subfeature(ExperimentTestSubfeatures.experimentTestAA))
181+
case .maliciousSiteProtection:
182+
return .remoteDevelopment(.subfeature(MaliciousSiteProtectionSubfeature.onByDefault))
177183
}
178184
}
179185
}

DuckDuckGo-iOS.xcodeproj/project.pbxproj

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -795,6 +795,8 @@
795795
98F3A1D8217B37010011A0D4 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98F3A1D7217B37010011A0D4 /* Theme.swift */; };
796796
98F6EA472863124100720957 /* ContentBlockerRulesLists.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98F6EA462863124100720957 /* ContentBlockerRulesLists.swift */; };
797797
98F78B8E22419093007CACF4 /* ThemableNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98F78B8D22419093007CACF4 /* ThemableNavigationController.swift */; };
798+
9F06EB752D09E8D200905426 /* MaliciousSiteProtectionFeatureFlags.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F06EB732D09E8D200905426 /* MaliciousSiteProtectionFeatureFlags.swift */; };
799+
9F06EB7B2D09EC2000905426 /* MaliciousSiteProtectionFeatureFlagsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F06EB792D09EC2000905426 /* MaliciousSiteProtectionFeatureFlagsTests.swift */; };
798800
9F16230B2CA0F0190093C4FC /* DebouncerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F16230A2CA0F0190093C4FC /* DebouncerTests.swift */; };
799801
9F1798572CD2443F0073018B /* AddToDockPromoViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F1798562CD2443F0073018B /* AddToDockPromoViewModelTests.swift */; };
800802
9F23B8012C2BC94400950875 /* OnboardingBackground.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F23B8002C2BC94400950875 /* OnboardingBackground.swift */; };
@@ -1086,8 +1088,6 @@
10861088
CBD4F13E279EBFAB00B20FD7 /* HomeMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBF14FC227970072001D94D0 /* HomeMessageView.swift */; };
10871089
CBD4F13F279EBFAF00B20FD7 /* HomeMessageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBF14FC427970AB0001D94D0 /* HomeMessageViewModel.swift */; };
10881090
CBD4F140279EBFB300B20FD7 /* SwiftUICollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB1AEFB02799AA940031AE3D /* SwiftUICollectionViewCell.swift */; };
1089-
CBD79F482D1061DA00DBB45A /* NewAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBD79F472D1061D500DBB45A /* NewAppDelegate.swift */; };
1090-
CBD79F4A2D1061E200DBB45A /* OldAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBD79F492D1061DF00DBB45A /* OldAppDelegate.swift */; };
10911091
CBD79F4D2D130F6500DBB45A /* AppTesting.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBD79F4C2D130F6300DBB45A /* AppTesting.swift */; };
10921092
CBDD5DDF29A6736A00832877 /* APIHeadersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBDD5DDE29A6736A00832877 /* APIHeadersTests.swift */; };
10931093
CBDD5DE129A6741300832877 /* MockBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBDD5DE029A6741300832877 /* MockBundle.swift */; };
@@ -2722,6 +2722,8 @@
27222722
98F3A1D7217B37010011A0D4 /* Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = "<group>"; };
27232723
98F6EA462863124100720957 /* ContentBlockerRulesLists.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentBlockerRulesLists.swift; sourceTree = "<group>"; };
27242724
98F78B8D22419093007CACF4 /* ThemableNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemableNavigationController.swift; sourceTree = "<group>"; };
2725+
9F06EB732D09E8D200905426 /* MaliciousSiteProtectionFeatureFlags.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaliciousSiteProtectionFeatureFlags.swift; sourceTree = "<group>"; };
2726+
9F06EB792D09EC2000905426 /* MaliciousSiteProtectionFeatureFlagsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaliciousSiteProtectionFeatureFlagsTests.swift; sourceTree = "<group>"; };
27252727
9F16230A2CA0F0190093C4FC /* DebouncerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebouncerTests.swift; sourceTree = "<group>"; };
27262728
9F1798562CD2443F0073018B /* AddToDockPromoViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddToDockPromoViewModelTests.swift; sourceTree = "<group>"; };
27272729
9F23B8002C2BC94400950875 /* OnboardingBackground.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingBackground.swift; sourceTree = "<group>"; };
@@ -3054,8 +3056,6 @@
30543056
CBC88EE42C8097B500F0F8C5 /* URLCredentialCreator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLCredentialCreator.swift; sourceTree = "<group>"; };
30553057
CBC8DC252AF6D4CD00BA681A /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/InfoPlist.strings; sourceTree = "<group>"; };
30563058
CBD4F13B279EBF4A00B20FD7 /* HomeMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeMessage.swift; sourceTree = "<group>"; };
3057-
CBD79F472D1061D500DBB45A /* NewAppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewAppDelegate.swift; sourceTree = "<group>"; };
3058-
CBD79F492D1061DF00DBB45A /* OldAppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OldAppDelegate.swift; sourceTree = "<group>"; };
30593059
CBD79F4C2D130F6300DBB45A /* AppTesting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppTesting.swift; sourceTree = "<group>"; };
30603060
CBD7AE812AF6D5B6009052FD /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/InfoPlist.strings; sourceTree = "<group>"; };
30613061
CBDD5DDE29A6736A00832877 /* APIHeadersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APIHeadersTests.swift; sourceTree = "<group>"; };
@@ -5248,6 +5248,22 @@
52485248
name = Themes;
52495249
sourceTree = "<group>";
52505250
};
5251+
9F06EB742D09E8D200905426 /* FeatureFlags */ = {
5252+
isa = PBXGroup;
5253+
children = (
5254+
9F06EB732D09E8D200905426 /* MaliciousSiteProtectionFeatureFlags.swift */,
5255+
);
5256+
path = FeatureFlags;
5257+
sourceTree = "<group>";
5258+
};
5259+
9F06EB7A2D09EC2000905426 /* MaliciousSiteProtection */ = {
5260+
isa = PBXGroup;
5261+
children = (
5262+
9F06EB792D09EC2000905426 /* MaliciousSiteProtectionFeatureFlagsTests.swift */,
5263+
);
5264+
path = MaliciousSiteProtection;
5265+
sourceTree = "<group>";
5266+
};
52515267
9F23B7FF2C2BABE000950875 /* OnboardingIntro */ = {
52525268
isa = PBXGroup;
52535269
children = (
@@ -5302,6 +5318,7 @@
53025318
9F254AA92CF47CD30063B308 /* MaliciousSiteProtection */ = {
53035319
isa = PBXGroup;
53045320
children = (
5321+
9F06EB742D09E8D200905426 /* FeatureFlags */,
53055322
9F254AAA2CF47DD50063B308 /* MaliciousSiteProtectionManager.swift */,
53065323
);
53075324
path = MaliciousSiteProtection;
@@ -6405,6 +6422,7 @@
64056422
83134D7F20E2E013006CE65D /* Feedback */,
64066423
8588026724E4249800C24AB6 /* iPad */,
64076424
851DFD88212C5ED600D95F20 /* Main */,
6425+
9F06EB7A2D09EC2000905426 /* MaliciousSiteProtection */,
64086426
EE56DE3A2A6038F500375C41 /* NetworkProtection */,
64096427
6F03CAFF2C32ED22004179A8 /* NewTabPage */,
64106428
F1D477C71F2139210031ED49 /* OmniBar */,
@@ -8430,6 +8448,7 @@
84308448
F13B4BC01F180D8A00814661 /* TabsModel.swift in Sources */,
84318449
8598D2E02CEB98B500C45685 /* Favicons.swift in Sources */,
84328450
8598D2E12CEB98B500C45685 /* NotFoundCachingDownloader.swift in Sources */,
8451+
9F06EB752D09E8D200905426 /* MaliciousSiteProtectionFeatureFlags.swift in Sources */,
84338452
8598D2E22CEB98B500C45685 /* FaviconRequestModifier.swift in Sources */,
84348453
CBAD0F102D0062A7006267B8 /* UIService.swift in Sources */,
84358454
8598D2E32CEB98B500C45685 /* FaviconUserScript.swift in Sources */,
@@ -8725,6 +8744,7 @@
87258744
83EDCC411F86B89C005CDFCD /* StatisticsLoaderTests.swift in Sources */,
87268745
564DE4572C4150E600D23241 /* NewTabPageControllerDaxDialogTests.swift in Sources */,
87278746
C14882E327F20D9A00D59F0C /* BookmarksExporterTests.swift in Sources */,
8747+
9F06EB7B2D09EC2000905426 /* MaliciousSiteProtectionFeatureFlagsTests.swift in Sources */,
87288748
85C29708247BDD060063A335 /* DaxDialogsBrowsingSpecTests.swift in Sources */,
87298749
9FE05CF12C36468A00D9046B /* OnboardingPixelReporterTests.swift in Sources */,
87308750
9FDEC7B42C8FD62F00C7A692 /* OnboardingAddressBarPositionPickerViewModelTests.swift in Sources */,
@@ -12133,8 +12153,8 @@
1213312153
isa = XCRemoteSwiftPackageReference;
1213412154
repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit.git";
1213512155
requirement = {
12136-
kind = exactVersion;
12137-
version = 234.0.0;
12156+
branch = "alessandro/malicious-site-protection-ios";
12157+
kind = branch;
1213812158
};
1213912159
};
1214012160
9F8FE9472BAE50E50071E372 /* XCRemoteSwiftPackageReference "lottie-spm" */ = {

DuckDuckGo-iOS.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 5 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

DuckDuckGo/AppLifecycle/AppStateTransitions.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ extension Initializing {
2424

2525
func apply(event: AppEvent) -> any AppState {
2626
guard case .didFinishLaunching(let application, let isTesting) = event else { return handleUnexpectedEvent(event) }
27-
return isTesting ? Testing(application: application) : Launching(stateContext: makeStateContext(application: application))
27+
return isTesting ? AppTesting(application: application) : Launching(stateContext: makeStateContext(application: application))
2828
}
2929

3030
}

DuckDuckGo/AppLifecycle/AppStates/AppTesting.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ struct AppTesting: AppState {
4646

4747
}
4848

49-
extension Testing {
49+
extension AppTesting {
5050

5151
mutating func handle(action: AppAction) { }
5252

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
//
2+
// MaliciousSiteProtectionFeatureFlags.swift
3+
// DuckDuckGo
4+
//
5+
// Copyright © 2024 DuckDuckGo. All rights reserved.
6+
//
7+
// Licensed under the Apache License, Version 2.0 (the "License");
8+
// you may not use this file except in compliance with the License.
9+
// You may obtain a copy of the License at
10+
//
11+
// http://www.apache.org/licenses/LICENSE-2.0
12+
//
13+
// Unless required by applicable law or agreed to in writing, software
14+
// distributed under the License is distributed on an "AS IS" BASIS,
15+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
// See the License for the specific language governing permissions and
17+
// limitations under the License.
18+
//
19+
20+
import Foundation
21+
import BrowserServicesKit
22+
import Core
23+
24+
protocol MaliciousSiteProtectionFeatureFlagger {
25+
/// A Boolean value indicating whether malicious site protection is enabled.
26+
/// - Returns: `true` if malicious site protection is enabled; otherwise, `false`.
27+
var isMaliciousSiteProtectionEnabled: Bool { get }
28+
29+
/// Checks if should detect malicious threats for a specific domain.
30+
/// - Parameter domain: The domain to check for malicious threat.
31+
/// - Returns: `true` if should check for malicious threats for the specified domain; otherwise, `false`.
32+
func shouldDetectMaliciousThreat(forDomain domain: String?) -> Bool
33+
}
34+
35+
protocol MaliciousSiteProtectionFeatureFlagsSettingsProvider {
36+
/// The frequency, in minutes, at which the hash prefix should be updated.
37+
var hashPrefixUpdateFrequency: Int { get }
38+
/// The frequency, in minutes, at which the filter set should be updated.
39+
var filterSetUpdateFrequency: Int { get }
40+
}
41+
42+
/// An enum representing the different settings for malicious site protection feature flags.
43+
enum MaliciousSiteProtectionFeatureSettings: String {
44+
/// The setting for hash prefix update frequency.
45+
case hashPrefixUpdateFrequency
46+
/// The setting for filter set update frequency.
47+
case filterSetUpdateFrequency
48+
49+
var defaultValue: Int {
50+
switch self {
51+
case .hashPrefixUpdateFrequency: return 20 // Default frequency for hash prefix updates is 20 minutes.
52+
case .filterSetUpdateFrequency: return 720 // Default frequency for filter set updates is 720 minutes (12 hours).
53+
}
54+
}
55+
}
56+
57+
final class MaliciousSiteProtectionFeatureFlags {
58+
private let featureFlagger: FeatureFlagger
59+
private let privacyConfigManager: PrivacyConfigurationManaging
60+
61+
private var remoteSettings: PrivacyConfigurationData.PrivacyFeature.FeatureSettings {
62+
privacyConfigManager.privacyConfig.settings(for: .maliciousSiteProtection)
63+
}
64+
65+
init(
66+
featureFlagger: FeatureFlagger = AppDependencyProvider.shared.featureFlagger,
67+
privacyConfigManager: PrivacyConfigurationManaging = ContentBlocking.shared.privacyConfigurationManager
68+
) {
69+
self.featureFlagger = featureFlagger
70+
self.privacyConfigManager = privacyConfigManager
71+
}
72+
}
73+
74+
// MARK: - MaliciousSiteProtectionFeatureFlagger
75+
76+
extension MaliciousSiteProtectionFeatureFlags: MaliciousSiteProtectionFeatureFlagger {
77+
78+
var isMaliciousSiteProtectionEnabled: Bool {
79+
featureFlagger.isFeatureOn(.maliciousSiteProtection)
80+
}
81+
82+
func shouldDetectMaliciousThreat(forDomain domain: String?) -> Bool {
83+
isMaliciousSiteProtectionEnabled && privacyConfigManager.privacyConfig.isFeature(.maliciousSiteProtection, enabledForDomain: domain)
84+
}
85+
86+
}
87+
88+
// MARK: - MaliciousSiteProtectionFeatureFlagsSettingsProvider
89+
90+
extension MaliciousSiteProtectionFeatureFlags: MaliciousSiteProtectionFeatureFlagsSettingsProvider {
91+
92+
var hashPrefixUpdateFrequency: Int {
93+
getSettings(MaliciousSiteProtectionFeatureSettings.hashPrefixUpdateFrequency)
94+
}
95+
96+
var filterSetUpdateFrequency: Int {
97+
getSettings(MaliciousSiteProtectionFeatureSettings.filterSetUpdateFrequency)
98+
}
99+
100+
private func getSettings(_ value: MaliciousSiteProtectionFeatureSettings) -> Int {
101+
remoteSettings[value.rawValue] as? Int ?? value.defaultValue
102+
}
103+
104+
}

0 commit comments

Comments
 (0)