From 1280d29505f2d24ed3e0336148047615f09f86aa Mon Sep 17 00:00:00 2001 From: Sam Symons Date: Fri, 27 Oct 2023 11:45:57 +0200 Subject: [PATCH 1/7] =?UTF-8?q?Add=20an=20=E2=80=9COpen=20VPN=20Settings?= =?UTF-8?q?=E2=80=9D=20quick=20action=20(#2089)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task/Issue URL: https://app.asana.com/0/414235014887631/1205784963805147/f Tech Design URL: CC: @graeme @diegoreymendez Description: This PR adds an iOS VPN quick action. --- DuckDuckGo.xcodeproj/project.pbxproj | 10 --- DuckDuckGo/AppDelegate.swift | 58 +++++++++++++++++- .../VPN-16.imageset/Contents.json | 15 +++++ .../VPN-16.imageset/VPN-16.pdf | Bin 0 -> 3623 bytes DuckDuckGo/UserText.swift | 2 + DuckDuckGo/en.lproj/Localizable.strings | 3 + 6 files changed, 76 insertions(+), 12 deletions(-) create mode 100644 DuckDuckGo/Assets.xcassets/VPN-16.imageset/Contents.json create mode 100644 DuckDuckGo/Assets.xcassets/VPN-16.imageset/VPN-16.pdf diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index fcd7e3b819..3241f608ca 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -1297,7 +1297,6 @@ 6AC6DAB228804F97002723C0 /* BarsAnimator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BarsAnimator.swift; sourceTree = ""; }; 6AC98418288055C1005FA9CA /* BarsAnimatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BarsAnimatorTests.swift; sourceTree = ""; }; 6FB030C7234331B400A10DB9 /* Configuration.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Configuration.xcconfig; path = Configuration/Configuration.xcconfig; sourceTree = ""; }; - 7B5E1F9D2AB9E1E900DA1172 /* NetworkProtectionDebugFeatures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionDebugFeatures.swift; sourceTree = ""; }; 83004E7F2193BB8200DA013C /* WKNavigationExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WKNavigationExtension.swift; sourceTree = ""; }; 83004E832193E14C00DA013C /* UIAlertControllerExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = UIAlertControllerExtension.swift; path = ../Core/UIAlertControllerExtension.swift; sourceTree = ""; }; 83004E852193E5ED00DA013C /* TabViewControllerBrowsingMenuExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabViewControllerBrowsingMenuExtension.swift; sourceTree = ""; }; @@ -3535,7 +3534,6 @@ 83ED3B8D1FA8E63700B47556 /* README.md */, 83ED3B8C1FA8E61D00B47556 /* ManualTestsScript.md */, 85A313962028E78A00327D00 /* release_notes.txt */, - EEF0F8CA2ABC82E100630031 /* Recovered References */, ); sourceTree = ""; }; @@ -4446,14 +4444,6 @@ name = Status; sourceTree = ""; }; - EEF0F8CA2ABC82E100630031 /* Recovered References */ = { - isa = PBXGroup; - children = ( - 7B5E1F9D2AB9E1E900DA1172 /* NetworkProtectionDebugFeatures.swift */, - ); - name = "Recovered References"; - sourceTree = ""; - }; EEFD562D2A65B68B00DAEC48 /* Invite */ = { isa = PBXGroup; children = ( diff --git a/DuckDuckGo/AppDelegate.swift b/DuckDuckGo/AppDelegate.swift index ee385aa81a..0b13604477 100644 --- a/DuckDuckGo/AppDelegate.swift +++ b/DuckDuckGo/AppDelegate.swift @@ -34,6 +34,10 @@ import Networking import DDGSync import SyncDataProviders +#if NETWORK_PROTECTION +import NetworkProtection +#endif + // swiftlint:disable file_length // swiftlint:disable type_body_length @@ -45,6 +49,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate { private struct ShortcutKey { static let clipboard = "com.duckduckgo.mobile.ios.clipboard" + +#if NETWORK_PROTECTION + static let openVPNSettings = "com.duckduckgo.mobile.ios.vpn.open-settings" +#endif } private var testing = false @@ -329,6 +337,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate { syncService.scheduler.notifyAppLifecycleEvent() fireFailedCompilationsPixelIfNeeded() + refreshShortcuts() + } + + func applicationWillResignActive(_ application: UIApplication) { + refreshShortcuts() } private func fireAppLaunchPixel() { @@ -591,11 +604,20 @@ class AppDelegate: UIResponder, UIApplicationDelegate { private func handleShortCutItem(_ shortcutItem: UIApplicationShortcutItem) { os_log("Handling shortcut item: %s", log: .generalLog, type: .debug, shortcutItem.type) - mainViewController?.clearNavigationStack() + autoClear?.applicationWillMoveToForeground() - if shortcutItem.type == ShortcutKey.clipboard, let query = UIPasteboard.general.string { + + if shortcutItem.type == ShortcutKey.clipboard, let query = UIPasteboard.general.string { + mainViewController?.clearNavigationStack() mainViewController?.loadQueryInNewTab(query) + return + } + +#if NETWORK_PROTECTION + if shortcutItem.type == ShortcutKey.openVPNSettings { + presentNetworkProtectionStatusSettingsModal() } +#endif } private func removeEmailWaitlistState() { @@ -623,6 +645,25 @@ class AppDelegate: UIResponder, UIApplicationDelegate { private var mainViewController: MainViewController? { return window?.rootViewController as? MainViewController } + + func refreshShortcuts() { +#if NETWORK_PROTECTION + guard NetworkProtectionKeychainTokenStore().isFeatureActivated else { + return + } + + let items = [ + UIApplicationShortcutItem(type: ShortcutKey.openVPNSettings, + localizedTitle: UserText.netPOpenVPNQuickAction, + localizedSubtitle: nil, + icon: UIApplicationShortcutIcon(templateImageName: "VPN-16"), + userInfo: nil) + ] + + UIApplication.shared.shortcutItems = items +#endif + } + } extension AppDelegate: BlankSnapshotViewRecoveringDelegate { @@ -708,6 +749,19 @@ extension AppDelegate: UNUserNotificationCenterDelegate { private func presentSettings(with viewController: UIViewController) { guard let window = window, let rootViewController = window.rootViewController as? MainViewController else { return } + if let navigationController = rootViewController.presentedViewController as? UINavigationController { + if let lastViewController = navigationController.viewControllers.last, lastViewController.isKind(of: type(of: viewController)) { + // Avoid presenting dismissing and re-presenting the view controller if it's already visible: + return + } else { + // Otherwise, replace existing view controllers with the presented one: + navigationController.popToRootViewController(animated: false) + navigationController.pushViewController(viewController, animated: false) + return + } + } + + // If the previous checks failed, make sure the nav stack is reset and present the view controller from scratch: rootViewController.clearNavigationStack() // Give the `clearNavigationStack` call time to complete. diff --git a/DuckDuckGo/Assets.xcassets/VPN-16.imageset/Contents.json b/DuckDuckGo/Assets.xcassets/VPN-16.imageset/Contents.json new file mode 100644 index 0000000000..eb05efadf9 --- /dev/null +++ b/DuckDuckGo/Assets.xcassets/VPN-16.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "VPN-16.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" + } +} diff --git a/DuckDuckGo/Assets.xcassets/VPN-16.imageset/VPN-16.pdf b/DuckDuckGo/Assets.xcassets/VPN-16.imageset/VPN-16.pdf new file mode 100644 index 0000000000000000000000000000000000000000..9b953299d8fca9202572b409b94907f035e73778 GIT binary patch literal 3623 zcma)5QX38SM*Dy1c`BXS6`(l5=jU`fCwAjA|8y_Nfvo+SUV{2>-nlZ?wQRZ z!90zRyX$i5RCUjz*Dqgv>Bc+^&RBE!^|!&8r%%nZXTx@Xtv?69#8=;M_wP?1i~wHg zs^jTyyS^P(FSmc*Y_?b5JU1`iEPri|!ykhiZF`KpynNZ;9{$(=+T0HP{o%`TvmeUE zo=cav+d;-0W68nHpdEdY6q9j&Of}k6H58YkPo|8~6)Dwhnzxu;1`F9sh;zUoK1hJ1 zi=#41j-)m1(*)TkAxp4rmCIEviMNiwbYJvE*Z3+@FZ*21in*Gs&r9pJ7Vq!*YaCwo zHGib)f(>GXU~Fh^yu*!{JSH0@g=VtGB*dA=EXlcZFyftORSrH8RZlCA<(yVWHqh*x zMCj`nh~`j0yw4F{Ku9nvvC-z>0{$pZbg4yEUCCraR6(kb#*IFCsR=|VM=c=Hib!E! z8moBn0m~V)-lQ?=wrV{4g7X%{73$_m-3Giw_C>5)3B?4WD#2zGDZGm!ycB>^6p60p ztf_1Hl+VJSHrm+es61vj)Y0aekbqLuu*%LPNq3f9imRql?tnRxCv{|mt%sP}A_O+G zE(C&h>{LODB5E6t#1N^M+L{o}#}{v{uzafh4or$~QikYQ914z21yzi5jX0?@I|#nU zP(!Sp*RsU?@6L{5e}+L1fg4~IE4nvwnPm9D^&{Y z5rP+03|rkuZ)B9OV2TAFKrW_|6%y;5YmiS#Y=a~sk+wBaeOObkQX}$oV@clD7CbFh zJqdwnMlECvOLfy`rhu+Q(>ROgG((keo<7=pZ1LitTUT#z;A^#rs6c%p&SUJ zusqHGd=4d}F`6D8+c`ljh?b^R?ib#scATNj@PXD0$!3)!g_DBH^f0naJf@+iNpnPI zNLA;ujwA}ecm(kgK?fZ*myx7(W>PG$-2f(x-PZ5{J|lAu)p;64#%djHu11-L96SiY z(>Ka+9O+55PbyJ7M;)cHv>!P^42)Zl&tun&h}Dap9en`ZY7~^8S=TX*%n3>$6|1vI zV8bVu@W1aS{bIw}h5lni4IP7u_HfWJ3InHHRC>->cM_QJdXUZM zt`edTRqd;~QMEPw-HlE!i=(?Q?~C#^>Z z*kp9F9_Flj44sEXT%ALWYqFm??6@>pq*nBF((`!wOSntuGb5Y9k513J1=fS^mO9e? zsaCqRd@*~AHRO(4D41N)aA%(oz=_Ma>&U`d$9k69J=4yA!}{LEy6yprb0w`giifc- z)UJ2>>B4@w-RnjEeCzkzH~Xa@$;}@FtFQL^!|7<={=&xr&+6yDe&3qa>-GEX1pKhQ zzF9v%d@^rmsdjnILvnt*Si0IC4`}nCSYR#%6^$!Nlj;MJR(zqdr+KIztXr Date: Fri, 27 Oct 2023 23:43:27 +1100 Subject: [PATCH 2/7] Update BSK with autofill 9.0.0 (#2103) Task/Issue URL: https://app.asana.com/0/1205747234047385/1205747234047385 Autofill Release: https://github.com/duckduckgo/duckduckgo-autofill/releases/tag/9.0.0 BSK PR: duckduckgo/BrowserServicesKit#537 Description Updates Autofill to version 9.0.0. --- DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 3241f608ca..73d7733850 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -8968,7 +8968,7 @@ repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 82.0.0; + version = 82.0.1; }; }; C14882EB27F211A000D59F0C /* XCRemoteSwiftPackageReference "SwiftSoup" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 571c464689..42760f18a2 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -15,8 +15,8 @@ "repositoryURL": "https://github.com/DuckDuckGo/BrowserServicesKit", "state": { "branch": null, - "revision": "dd595d952e0076a7a01d086ed2424838dcd985af", - "version": "82.0.0" + "revision": "8f7a94a70812862203955b3d2bbb909420fa55dd", + "version": "82.0.1" } }, { @@ -51,8 +51,8 @@ "repositoryURL": "https://github.com/duckduckgo/duckduckgo-autofill.git", "state": { "branch": null, - "revision": "6dd7d696d4e666cedb2f1890a46fe53615226646", - "version": "8.4.2" + "revision": "c8e895c8fd50dc76e8d8dc827a636ad77b7f46ff", + "version": "9.0.0" } }, { From 8e959f383e9c95564aaeca5a450132ddda03ede2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20=C5=81yp?= Date: Mon, 30 Oct 2023 16:05:32 +0100 Subject: [PATCH 3/7] Switch to next phase of new experiment for UA (#2118) --- Core/DefaultVariantManager.swift | 7 +++++-- Core/UserAgentManager.swift | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Core/DefaultVariantManager.swift b/Core/DefaultVariantManager.swift index 7539b2981b..158b52d99d 100644 --- a/Core/DefaultVariantManager.swift +++ b/Core/DefaultVariantManager.swift @@ -27,6 +27,7 @@ extension FeatureName { // public static let experimentalFeature = FeatureName(rawValue: "experimentalFeature") public static let fixedUserAgent = FeatureName(rawValue: "fixedUserAgent") + public static let closestUserAgent = FeatureName(rawValue: "closestUserAgent") } public struct VariantIOS: Variant { @@ -61,8 +62,10 @@ public struct VariantIOS: Variant { VariantIOS(name: "sc", weight: doNotAllocate, isIncluded: When.always, features: []), VariantIOS(name: "sd", weight: doNotAllocate, isIncluded: When.always, features: []), VariantIOS(name: "se", weight: doNotAllocate, isIncluded: When.always, features: []), - VariantIOS(name: "me", weight: 1, isIncluded: When.always, features: []), - VariantIOS(name: "mf", weight: 1, isIncluded: When.always, features: [.fixedUserAgent]), + VariantIOS(name: "me", weight: doNotAllocate, isIncluded: When.always, features: []), + VariantIOS(name: "mf", weight: doNotAllocate, isIncluded: When.always, features: []), + VariantIOS(name: "mg", weight: 1, isIncluded: When.always, features: [.fixedUserAgent]), + VariantIOS(name: "mh", weight: 1, isIncluded: When.always, features: [.closestUserAgent]), returningUser ] diff --git a/Core/UserAgentManager.swift b/Core/UserAgentManager.swift index 0e03659e2e..6434f24758 100644 --- a/Core/UserAgentManager.swift +++ b/Core/UserAgentManager.swift @@ -212,6 +212,8 @@ struct UserAgent { if DefaultVariantManager().isSupported(feature: .fixedUserAgent) { return ddgFixedLogic(forUrl: url, isDesktop: isDesktop, privacyConfig: privacyConfig) + } else if DefaultVariantManager().isSupported(feature: .closestUserAgent) { + return closestLogic(forUrl: url, isDesktop: isDesktop, privacyConfig: privacyConfig) } switch defaultPolicy(forConfig: privacyConfig) { From 784f05aa2fe90ec99295ca9885d27f3bbb443d47 Mon Sep 17 00:00:00 2001 From: Diego Rey Mendez Date: Tue, 31 Oct 2023 00:23:01 +0100 Subject: [PATCH 4/7] Integrates the latest DBP changes in BSK (#2108) Task/Issue URL: https://app.asana.com/0/0/1205755216985387/f BSK PR: https://github.com/duckduckgo/BrowserServicesKit/pull/532 macOS PR: https://github.com/duckduckgo/macos-browser/pull/1751 ## Description Integrates the latest BSK changes. --- Core/Core.h | 1 - DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 6 +++--- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Core/Core.h b/Core/Core.h index 8d22735937..ac21b9bd95 100644 --- a/Core/Core.h +++ b/Core/Core.h @@ -19,7 +19,6 @@ #import -#import "BloomFilterWrapper.h" //! Project version number for Core. diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 73d7733850..a18515068d 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -8968,7 +8968,7 @@ repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 82.0.1; + version = 82.0.2; }; }; C14882EB27F211A000D59F0C /* XCRemoteSwiftPackageReference "SwiftSoup" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 42760f18a2..525be5fff2 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -15,8 +15,8 @@ "repositoryURL": "https://github.com/DuckDuckGo/BrowserServicesKit", "state": { "branch": null, - "revision": "8f7a94a70812862203955b3d2bbb909420fa55dd", - "version": "82.0.1" + "revision": "8768193257dd1f461218ed2a8d7893156bde4bda", + "version": "82.0.2" } }, { @@ -156,7 +156,7 @@ }, { "package": "TrackerRadarKit", - "repositoryURL": "https://github.com/duckduckgo/TrackerRadarKit.git", + "repositoryURL": "https://github.com/duckduckgo/TrackerRadarKit", "state": { "branch": null, "revision": "4684440d03304e7638a2c8086895367e90987463", From ce8ce7538ce5cbfe915d334d758fa3dc2b9b37c2 Mon Sep 17 00:00:00 2001 From: amddg44 Date: Tue, 31 Oct 2023 08:27:26 +0100 Subject: [PATCH 5/7] Fix for deeplink crash when preparing webview preview (#2116) Task/Issue URL: https://app.asana.com/0/414709148257752/1205793869765618/f Tech Design URL: CC: Description: When launching the app from deeplink the webView size can be 0,0 causing UIGraphicsBeginImageContextWithOptions to crash --- DuckDuckGo/TabViewController.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/DuckDuckGo/TabViewController.swift b/DuckDuckGo/TabViewController.swift index 2ba270fa41..04a448e738 100644 --- a/DuckDuckGo/TabViewController.swift +++ b/DuckDuckGo/TabViewController.swift @@ -1094,7 +1094,8 @@ extension TabViewController: WKNavigationDelegate { func preparePreview(completion: @escaping (UIImage?) -> Void) { DispatchQueue.main.async { [weak self] in - guard let webView = self?.webView else { completion(nil); return } + guard let webView = self?.webView, + webView.bounds.height > 0 && webView.bounds.width > 0 else { completion(nil); return } UIGraphicsBeginImageContextWithOptions(webView.bounds.size, false, UIScreen.main.scale) webView.drawHierarchy(in: webView.bounds, afterScreenUpdates: true) if let jsAlertController = self?.jsAlertController { From ff096da69dd0298fc1cba1fdd7c87efad5c01872 Mon Sep 17 00:00:00 2001 From: Graeme Arthur Date: Tue, 31 Oct 2023 18:51:04 +0100 Subject: [PATCH 6/7] Add toggling of NetP Notifications to iOS (#2112) Co-authored-by: Sam Symons --- Core/UserDefaults+NetworkProtection.swift | 34 +++++++ DuckDuckGo.xcodeproj/project.pbxproj | 30 ++++++- .../xcshareddata/swiftpm/Package.resolved | 4 +- DuckDuckGo/DuckDuckGo.entitlements | 1 + ...orkProtectionConvenienceInitialisers.swift | 10 +++ DuckDuckGo/NetworkProtectionStatusView.swift | 9 +- .../NetworkProtectionStatusViewModel.swift | 6 ++ ...etworkProtectionVPNNotificationsView.swift | 90 +++++++++++++++++++ ...kProtectionVPNNotificationsViewModel.swift | 79 ++++++++++++++++ ...NotificationsAuthorizationController.swift | 87 ++++++++++++++++++ DuckDuckGo/UIApplicationExtension.swift | 41 +++++++++ DuckDuckGo/UserText.swift | 4 + DuckDuckGo/en.lproj/Localizable.strings | 12 +++ ...etworkProtectionPacketTunnelProvider.swift | 11 ++- .../PacketTunnelProvider.entitlements | 1 + 15 files changed, 412 insertions(+), 7 deletions(-) create mode 100644 Core/UserDefaults+NetworkProtection.swift create mode 100644 DuckDuckGo/NetworkProtectionVPNNotificationsView.swift create mode 100644 DuckDuckGo/NetworkProtectionVPNNotificationsViewModel.swift create mode 100644 DuckDuckGo/NotificationsAuthorizationController.swift create mode 100644 DuckDuckGo/UIApplicationExtension.swift diff --git a/Core/UserDefaults+NetworkProtection.swift b/Core/UserDefaults+NetworkProtection.swift new file mode 100644 index 0000000000..fb9def1004 --- /dev/null +++ b/Core/UserDefaults+NetworkProtection.swift @@ -0,0 +1,34 @@ +// +// UserDefaults+NetworkProtection.swift +// DuckDuckGo +// +// Copyright © 2023 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. +// + +#if NETWORK_PROTECTION + +import Foundation + +public extension UserDefaults { + static var networkProtectionGroupDefaults: UserDefaults { + let suiteName = "\(Global.groupIdPrefix).netp" + guard let defaults = UserDefaults(suiteName: suiteName) else { + fatalError("Failed to create netP UserDefaults") + } + return defaults + } +} + +#endif diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index a18515068d..fac3670a7d 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -765,6 +765,11 @@ EE8594992A44791C008A6D06 /* NetworkProtectionTunnelController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE8594982A44791C008A6D06 /* NetworkProtectionTunnelController.swift */; }; EE8E568A2A56BCE400F11DCA /* NetworkProtection in Frameworks */ = {isa = PBXBuildFile; productRef = EE8E56892A56BCE400F11DCA /* NetworkProtection */; }; EE9D68D12AE00CF300B55EF4 /* NetworkProtectionVPNSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE9D68D02AE00CF300B55EF4 /* NetworkProtectionVPNSettingsView.swift */; }; + EE9D68D52AE1526600B55EF4 /* NetworkProtectionVPNNotificationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE9D68D42AE1526600B55EF4 /* NetworkProtectionVPNNotificationsView.swift */; }; + EE9D68D82AE15AD600B55EF4 /* UIApplicationExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE9D68D72AE15AD600B55EF4 /* UIApplicationExtension.swift */; }; + EE9D68DA2AE1659F00B55EF4 /* NetworkProtectionVPNNotificationsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE9D68D92AE1659F00B55EF4 /* NetworkProtectionVPNNotificationsViewModel.swift */; }; + EE9D68DC2AE16AE100B55EF4 /* NotificationsAuthorizationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE9D68DB2AE16AE100B55EF4 /* NotificationsAuthorizationController.swift */; }; + EE9D68DE2AE2A65600B55EF4 /* UserDefaults+NetworkProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE9D68DD2AE2A65600B55EF4 /* UserDefaults+NetworkProtection.swift */; }; EEDFE2DA2AC6ED4F00F0E19C /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = EEDFE2DC2AC6ED4F00F0E19C /* Localizable.strings */; }; EEEB80A32A421CE600386378 /* NetworkProtectionPacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEEB80A22A421CE600386378 /* NetworkProtectionPacketTunnelProvider.swift */; }; EEF0F8CC2ABC832300630031 /* NetworkProtectionDebugFeatures.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEF0F8CB2ABC832200630031 /* NetworkProtectionDebugFeatures.swift */; }; @@ -2333,6 +2338,11 @@ EE7A92862AC6DE4700832A36 /* NetworkProtectionNotificationIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionNotificationIdentifier.swift; sourceTree = ""; }; EE8594982A44791C008A6D06 /* NetworkProtectionTunnelController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionTunnelController.swift; sourceTree = ""; }; EE9D68D02AE00CF300B55EF4 /* NetworkProtectionVPNSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionVPNSettingsView.swift; sourceTree = ""; }; + EE9D68D42AE1526600B55EF4 /* NetworkProtectionVPNNotificationsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionVPNNotificationsView.swift; sourceTree = ""; }; + EE9D68D72AE15AD600B55EF4 /* UIApplicationExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIApplicationExtension.swift; sourceTree = ""; }; + EE9D68D92AE1659F00B55EF4 /* NetworkProtectionVPNNotificationsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionVPNNotificationsViewModel.swift; sourceTree = ""; }; + EE9D68DB2AE16AE100B55EF4 /* NotificationsAuthorizationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsAuthorizationController.swift; sourceTree = ""; }; + EE9D68DD2AE2A65600B55EF4 /* UserDefaults+NetworkProtection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults+NetworkProtection.swift"; sourceTree = ""; }; EEB8FDB92A990AEE00EBEDCF /* Configuration-Alpha.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Configuration-Alpha.xcconfig"; path = "Configuration/Configuration-Alpha.xcconfig"; sourceTree = ""; }; EEDFE2DB2AC6ED4F00F0E19C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; EEDFE2DD2AC6ED5B00F0E19C /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/Localizable.strings; sourceTree = ""; }; @@ -4346,6 +4356,7 @@ children = ( EE0153E02A6EABE0002A8B26 /* NetworkProtectionConvenienceInitialisers.swift */, EE458D0C2AB1DA4600FC651A /* EventMapping+NetworkProtectionError.swift */, + EE9D68DB2AE16AE100B55EF4 /* NotificationsAuthorizationController.swift */, ); name = Helpers; sourceTree = ""; @@ -4409,6 +4420,7 @@ isa = PBXGroup; children = ( EE7A92862AC6DE4700832A36 /* NetworkProtectionNotificationIdentifier.swift */, + EE9D68DD2AE2A65600B55EF4 /* UserDefaults+NetworkProtection.swift */, ); name = NetworkProtection; sourceTree = ""; @@ -4421,9 +4433,19 @@ name = VPNSettings; sourceTree = ""; }; + EE9D68D62AE1527F00B55EF4 /* VPNNotifications */ = { + isa = PBXGroup; + children = ( + EE9D68D42AE1526600B55EF4 /* NetworkProtectionVPNNotificationsView.swift */, + EE9D68D92AE1659F00B55EF4 /* NetworkProtectionVPNNotificationsViewModel.swift */, + ); + name = VPNNotifications; + sourceTree = ""; + }; EECD94B22A28B8580085C66E /* NetworkProtection */ = { isa = PBXGroup; children = ( + EE9D68D62AE1527F00B55EF4 /* VPNNotifications */, EE9D68CF2AE00CE000B55EF4 /* VPNSettings */, EE458D122ABB651500FC651A /* Debug */, EE0153E22A6FE031002A8B26 /* Root */, @@ -5098,6 +5120,7 @@ F1DE78591E5CD2A70058895A /* UIViewExtension.swift */, F1F5337B1F26A9EF00D80D4F /* UserText.swift */, 986DA94924884B18004A7E39 /* WebViewTransition.swift */, + EE9D68D72AE15AD600B55EF4 /* UIApplicationExtension.swift */, ); name = UserInterface; sourceTree = ""; @@ -6104,6 +6127,7 @@ F1DE78581E5CAE350058895A /* TabViewGridCell.swift in Sources */, 984D035824ACCC6F0066CFB8 /* TabViewListCell.swift in Sources */, B6BA95C328891E33004ABA20 /* BrowsingMenuAnimator.swift in Sources */, + EE9D68DC2AE16AE100B55EF4 /* NotificationsAuthorizationController.swift in Sources */, AA3D854923DA1DFB00788410 /* AppIcon.swift in Sources */, 8590CB612684D0600089F6BF /* CookieDebugViewController.swift in Sources */, 319A37152829A55F0079FBCE /* AutofillListItemTableViewCell.swift in Sources */, @@ -6125,6 +6149,7 @@ 1E8AD1C727BE9B2900ABA377 /* DownloadsListDataSource.swift in Sources */, 3157B43527F497F50042D3D7 /* SaveLoginViewController.swift in Sources */, 853C5F6121C277C7001F7A05 /* global.swift in Sources */, + EE9D68D82AE15AD600B55EF4 /* UIApplicationExtension.swift in Sources */, F13B4BD31F1822C700814661 /* Tab.swift in Sources */, F1BE54581E69DE1000FCF649 /* TutorialSettings.swift in Sources */, 1EE52ABB28FB1D6300B750C1 /* UIImageExtension.swift in Sources */, @@ -6146,6 +6171,7 @@ C1B7B529289420830098FD6A /* RemoteMessaging.xcdatamodeld in Sources */, 986B16C425E92DF0007D23E8 /* BrowsingMenuViewController.swift in Sources */, 988AC355257E47C100793C64 /* RequeryLogic.swift in Sources */, + EE9D68D52AE1526600B55EF4 /* NetworkProtectionVPNNotificationsView.swift in Sources */, 1E4F4A5A297193DE00625985 /* MainViewController+CookiesManaged.swift in Sources */, 8586A10D24CBA7070049720E /* FindInPageActivity.swift in Sources */, 1E1626072968413B0004127F /* ViewExtension.swift in Sources */, @@ -6430,6 +6456,7 @@ 8586A11024CCCD040049720E /* TabsBarViewController.swift in Sources */, F1D796F41E7C2A410019D451 /* BookmarksDelegate.swift in Sources */, C1B7B52428941F2A0098FD6A /* RemoteMessageRequest.swift in Sources */, + EE9D68DA2AE1659F00B55EF4 /* NetworkProtectionVPNNotificationsViewModel.swift in Sources */, 1E8AD1D727C2E24E00ABA377 /* DownloadsListRowViewModel.swift in Sources */, C1B0F6422AB08BE9001EAF05 /* MockPrivacyConfiguration.swift in Sources */, 1E865AF0272042DB001C74F3 /* TextSizeSettingsViewController.swift in Sources */, @@ -6689,6 +6716,7 @@ CB2A7EF4285383B300885F67 /* AppLastCompiledRulesStore.swift in Sources */, 4B75EA9226A266CB00018634 /* PrintingUserScript.swift in Sources */, 37445F972A155F7C0029F789 /* SyncDataProviders.swift in Sources */, + EE9D68DE2AE2A65600B55EF4 /* UserDefaults+NetworkProtection.swift in Sources */, CB258D1F29A52B2500DEBA24 /* Configuration.swift in Sources */, 9847C00027A2DDBB00DB07AA /* AppPrivacyConfigurationDataProvider.swift in Sources */, F143C3281E4A9A0E00CFDE3A /* StringExtension.swift in Sources */, @@ -8968,7 +8996,7 @@ repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 82.0.2; + version = 82.1.0; }; }; C14882EB27F211A000D59F0C /* XCRemoteSwiftPackageReference "SwiftSoup" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 525be5fff2..0836aa38a9 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -15,8 +15,8 @@ "repositoryURL": "https://github.com/DuckDuckGo/BrowserServicesKit", "state": { "branch": null, - "revision": "8768193257dd1f461218ed2a8d7893156bde4bda", - "version": "82.0.2" + "revision": "71e916d070cedcba9ccb3ce9431797260bf5cbea", + "version": "82.1.0" } }, { diff --git a/DuckDuckGo/DuckDuckGo.entitlements b/DuckDuckGo/DuckDuckGo.entitlements index 3b229351b9..82bd4ed6cd 100644 --- a/DuckDuckGo/DuckDuckGo.entitlements +++ b/DuckDuckGo/DuckDuckGo.entitlements @@ -15,6 +15,7 @@ $(GROUP_ID_PREFIX).statistics $(GROUP_ID_PREFIX).database $(GROUP_ID_PREFIX).apptp + $(GROUP_ID_PREFIX).netp diff --git a/DuckDuckGo/NetworkProtectionConvenienceInitialisers.swift b/DuckDuckGo/NetworkProtectionConvenienceInitialisers.swift index 248b52aa81..0587a405b8 100644 --- a/DuckDuckGo/NetworkProtectionConvenienceInitialisers.swift +++ b/DuckDuckGo/NetworkProtectionConvenienceInitialisers.swift @@ -58,4 +58,14 @@ extension NetworkProtectionCodeRedemptionCoordinator { } } +extension NetworkProtectionVPNNotificationsViewModel { + convenience init() { + let notificationsSettingsStore = NetworkProtectionNotificationsSettingsUserDefaultsStore(userDefaults: .networkProtectionGroupDefaults) + self.init( + notificationsAuthorization: NotificationsAuthorizationController(), + notificationsSettingsStore: notificationsSettingsStore + ) + } +} + #endif diff --git a/DuckDuckGo/NetworkProtectionStatusView.swift b/DuckDuckGo/NetworkProtectionStatusView.swift index c7b1e13dcf..de8c854726 100644 --- a/DuckDuckGo/NetworkProtectionStatusView.swift +++ b/DuckDuckGo/NetworkProtectionStatusView.swift @@ -40,9 +40,12 @@ struct NetworkProtectionStatusView: View { } settings() } - .animation(.default, value: statusModel.shouldShowError) .padding(.top, statusModel.error == nil ? 0 : -20) - .animation(.default, value: statusModel.shouldShowConnectionDetails) + .if(statusModel.animationsOn, transform: { + $0 + .animation(.default, value: statusModel.shouldShowConnectionDetails) + .animation(.default, value: statusModel.shouldShowError) + }) .applyInsetGroupedListStyle() .navigationTitle(UserText.netPNavTitle) } @@ -134,7 +137,7 @@ struct NetworkProtectionStatusView: View { NavigationLink(UserText.netPVPNSettingsTitle, destination: NetworkProtectionVPNSettingsView()) .font(.system(size: 16)) .foregroundColor(.textPrimary) - NavigationLink(UserText.netPVPNNotificationsTitle, destination: Text("Coming soon!")) + NavigationLink(UserText.netPVPNNotificationsTitle, destination: NetworkProtectionVPNNotificationsView()) .font(.system(size: 16)) .foregroundColor(.textPrimary) } header: { diff --git a/DuckDuckGo/NetworkProtectionStatusViewModel.swift b/DuckDuckGo/NetworkProtectionStatusViewModel.swift index 3ee41e6b67..dc8924c38b 100644 --- a/DuckDuckGo/NetworkProtectionStatusViewModel.swift +++ b/DuckDuckGo/NetworkProtectionStatusViewModel.swift @@ -65,6 +65,8 @@ final class NetworkProtectionStatusViewModel: ObservableObject { @Published public var location: String? @Published public var ipAddress: String? + @Published public var animationsOn: Bool = false + public init(tunnelController: TunnelController = NetworkProtectionTunnelController(), statusObserver: ConnectionStatusObserver = ConnectionStatusObserverThroughSession(), serverInfoObserver: ConnectionServerInfoObserver = ConnectionServerInfoObserverThroughSession(), @@ -166,7 +168,11 @@ final class NetworkProtectionStatusViewModel: ObservableObject { .store(in: &cancellables) } + @MainActor func didToggleNetP(to enabled: Bool) async { + // This is to prevent weird looking animations on navigating to the screen. + // It makes sense as animations should mostly only happen when a user has interacted. + animationsOn = true if enabled { await enableNetP() } else { diff --git a/DuckDuckGo/NetworkProtectionVPNNotificationsView.swift b/DuckDuckGo/NetworkProtectionVPNNotificationsView.swift new file mode 100644 index 0000000000..d5b0d22fd2 --- /dev/null +++ b/DuckDuckGo/NetworkProtectionVPNNotificationsView.swift @@ -0,0 +1,90 @@ +// +// NetworkProtectionVPNNotificationsView.swift +// DuckDuckGo +// +// Copyright © 2023 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. +// + +#if NETWORK_PROTECTION + +import SwiftUI +import UIKit +import NetworkProtection +import Core + +@available(iOS 15, *) +struct NetworkProtectionVPNNotificationsView: View { + @StateObject var model = NetworkProtectionVPNNotificationsViewModel() + + var body: some View { + List { + switch model.viewKind { + case .loading: + EmptyView() + case .unauthorized: + unauthorizedView + case .authorized: + authorizedView + } + } + .animation(.default, value: model.viewKind) + .applyInsetGroupedListStyle() + .navigationTitle(UserText.netPVPNNotificationsTitle).onAppear { + Task { + await model.onViewAppeared() + } + } + } + + @ViewBuilder + private var unauthorizedView: some View { + Section { + Button(UserText.netPTurnOnNotificationsButtonTitle) { + model.turnOnNotifications() + } + .foregroundColor(.controlColor) + } footer: { + Text(UserText.netPTurnOnNotificationsSectionFooter) + .foregroundColor(.textSecondary) + .font(.system(size: 13)) + .padding(.top, 6) + } + } + + @ViewBuilder + private var authorizedView: some View { + Section { + Toggle(UserText.netPVPNAlertsToggleTitle, isOn: Binding( + get: { model.alertsEnabled }, + set: model.didToggleAlerts(to:) + )) + .toggleStyle(SwitchToggleStyle(tint: .controlColor)) + } footer: { + Text(UserText.netPVPNAlertsToggleSectionFooter) + .foregroundColor(.textSecondary) + .font(.system(size: 13)) + .padding(.top, 6) + } + } +} + +private extension Color { + static let textPrimary = Color(designSystemColor: .textPrimary) + static let textSecondary = Color(designSystemColor: .textSecondary) + static let cellBackground = Color(designSystemColor: .surface) + static let controlColor = Color(designSystemColor: .accent) +} + +#endif diff --git a/DuckDuckGo/NetworkProtectionVPNNotificationsViewModel.swift b/DuckDuckGo/NetworkProtectionVPNNotificationsViewModel.swift new file mode 100644 index 0000000000..62833eb25a --- /dev/null +++ b/DuckDuckGo/NetworkProtectionVPNNotificationsViewModel.swift @@ -0,0 +1,79 @@ +// +// NetworkProtectionVPNNotificationsViewModel.swift +// DuckDuckGo +// +// Copyright © 2023 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. +// + +#if NETWORK_PROTECTION + +import Combine +import UserNotifications +import NetworkProtection + +enum NetworkProtectionNotificationsViewKind: Equatable { + case loading + case unauthorized + case authorized +} + +final class NetworkProtectionVPNNotificationsViewModel: ObservableObject { + private var notificationsAuthorization: NotificationsAuthorizationControlling + private var notificationsSettingsStore: NetworkProtectionNotificationsSettingsStore + @Published var viewKind: NetworkProtectionNotificationsViewKind = .loading + var alertsEnabled: Bool { + self.notificationsSettingsStore.alertsEnabled + } + + init(notificationsAuthorization: NotificationsAuthorizationControlling, + notificationsSettingsStore: NetworkProtectionNotificationsSettingsStore) { + self.notificationsAuthorization = notificationsAuthorization + self.notificationsSettingsStore = notificationsSettingsStore + self.notificationsAuthorization.delegate = self + } + + @MainActor + func onViewAppeared() async { + let status = await notificationsAuthorization.authorizationStatus + updateViewKind(for: status) + } + + func turnOnNotifications() { + notificationsAuthorization.requestAlertAuthorization() + } + + func didToggleAlerts(to enabled: Bool) { + notificationsSettingsStore.alertsEnabled = enabled + } + + private func updateViewKind(for authorizationStatus: UNAuthorizationStatus) { + switch authorizationStatus { + case .notDetermined, .denied: + viewKind = .unauthorized + case .authorized, .ephemeral, .provisional: + viewKind = .authorized + @unknown default: + assertionFailure("Unhandled enum case") + } + } +} + +extension NetworkProtectionVPNNotificationsViewModel: NotificationsPermissionsControllerDelegate { + func authorizationStateDidChange(toStatus status: UNAuthorizationStatus) { + updateViewKind(for: status) + } +} + +#endif diff --git a/DuckDuckGo/NotificationsAuthorizationController.swift b/DuckDuckGo/NotificationsAuthorizationController.swift new file mode 100644 index 0000000000..a5524a4cc9 --- /dev/null +++ b/DuckDuckGo/NotificationsAuthorizationController.swift @@ -0,0 +1,87 @@ +// +// NotificationsAuthorizationController.swift +// DuckDuckGo +// +// Copyright © 2023 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 UserNotifications +import UIKit +import Combine + +protocol NotificationsAuthorizationControlling { + var authorizationStatus: UNAuthorizationStatus { get async } + var delegate: NotificationsPermissionsControllerDelegate? { get set } + + func requestAlertAuthorization() +} + +protocol NotificationsPermissionsControllerDelegate: AnyObject { + func authorizationStateDidChange(toStatus status: UNAuthorizationStatus) +} + +final class NotificationsAuthorizationController: NotificationsAuthorizationControlling { + + weak var delegate: NotificationsPermissionsControllerDelegate? + var notificationCancellable: AnyCancellable? + + var authorizationStatus: UNAuthorizationStatus { + get async { + let settings: UNNotificationSettings = await UNUserNotificationCenter.current().notificationSettings() + return settings.authorizationStatus + } + } + + init() { + // To handle navigating back from iOS Settings after changing the authorization + notificationCancellable = NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification) + .sink { _ in + Task { [weak self] in + await self?.updateDelegateWithNewState() + } + } + } + + func requestAlertAuthorization() { + Task { + switch await authorizationStatus { + case .notDetermined: + await requestAuthorization(options: .alert) + case .denied: + _ = await UIApplication.shared.openAppNotificationSettings() + case .authorized, .provisional, .ephemeral: + break + @unknown default: + break + } + } + } + + private func requestAuthorization(options: UNAuthorizationOptions) async { + do { + let authorized = try await UNUserNotificationCenter.current().requestAuthorization(options: options) + if authorized { + await updateDelegateWithNewState() + } + } catch { } + } + + private func updateDelegateWithNewState() async { + let newState = await authorizationStatus + DispatchQueue.main.async { [weak self] in + self?.delegate?.authorizationStateDidChange(toStatus: newState) + } + } +} diff --git a/DuckDuckGo/UIApplicationExtension.swift b/DuckDuckGo/UIApplicationExtension.swift new file mode 100644 index 0000000000..c89cabd385 --- /dev/null +++ b/DuckDuckGo/UIApplicationExtension.swift @@ -0,0 +1,41 @@ +// +// UIApplicationExtension.swift +// DuckDuckGo +// +// Copyright © 2023 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 UIKit + +extension UIApplication { + private static let notificationSettingsURL: URL? = { + let settingsString: String + if #available(iOS 16, *) { + settingsString = UIApplication.openNotificationSettingsURLString + } else if #available(iOS 15.4, *) { + settingsString = UIApplicationOpenNotificationSettingsURLString + } else { + settingsString = UIApplication.openSettingsURLString + } + return URL(string: settingsString) + }() + + func openAppNotificationSettings() async -> Bool { + guard + let url = UIApplication.notificationSettingsURL, + self.canOpenURL(url) else { return false } + return await self.open(url) + } +} diff --git a/DuckDuckGo/UserText.swift b/DuckDuckGo/UserText.swift index 8d2331337d..0447b01e09 100644 --- a/DuckDuckGo/UserText.swift +++ b/DuckDuckGo/UserText.swift @@ -656,6 +656,10 @@ In addition to the details entered into this form, your app issue report will co static let netPAlwaysOnSettingFooter = NSLocalizedString("network.protection.vpn.always.on.setting.footer", value: "Automatically restore a VPN connection after interruption.", comment: "Footer text for the Always on VPN setting item.") static let netPSecureDNSSettingTitle = NSLocalizedString("network.protection.vpn.secure.dns.setting.title", value: "Secure DNS", comment: "Title for the Always on VPN setting item.") static let netPSecureDNSSettingFooter = NSLocalizedString("network.protection.vpn.secure.dns.setting.footer", value: "Network Protection prevents DNS leaks to your Internet Service Provider by routing DNS queries though the VPN tunnel to our own resolver.", comment: "Footer text for the Always on VPN setting item.") + static let netPTurnOnNotificationsButtonTitle = NSLocalizedString("network.protection.turn.on.notifications.button.title", value: "Turn on Notifications", comment: "Title for the button to link to the iOS app settings and enable notifications app-wide.") + static let netPTurnOnNotificationsSectionFooter = NSLocalizedString("network.protection.turn.on.notifications.section.footer", value: "Allow DuckDuckGo to notify you if your connection drops or VPN status changes.", comment: "Footer text under the button to link to the iOS app settings and enable notifications app-wide.") + static let netPVPNAlertsToggleTitle = NSLocalizedString("network.protection.vpn.alerts.toggle.title", value: "VPN Alerts", comment: "Title for the toggle for VPN alerts.") + static let netPVPNAlertsToggleSectionFooter = NSLocalizedString("network.protection.vpn.alerts.toggle.section.footer", value: "Get notified if your connection drops or VPN status changes.", comment: "List section footer for the toggle for VPN alerts.") static let netPOpenVPNQuickAction = NSLocalizedString("network.protection.quick-action.open-vpn", value: "Open VPN", comment: "Title text for an iOS quick action that opens VPN settings") diff --git a/DuckDuckGo/en.lproj/Localizable.strings b/DuckDuckGo/en.lproj/Localizable.strings index b966ba574d..bdcc498b88 100644 --- a/DuckDuckGo/en.lproj/Localizable.strings +++ b/DuckDuckGo/en.lproj/Localizable.strings @@ -1441,6 +1441,18 @@ https://duckduckgo.com/mac"; /* Title label text for the status view when netP is disconnected */ "network.protection.status.view.title" = "Network Protection"; +/* Title for the button to link to the iOS app settings and enable notifications app-wide. */ +"network.protection.turn.on.notifications.button.title" = "Turn on Notifications"; + +/* Footer text under the button to link to the iOS app settings and enable notifications app-wide. */ +"network.protection.turn.on.notifications.section.footer" = "Allow DuckDuckGo to notify you if your connection drops or VPN status changes."; + +/* List section footer for the toggle for VPN alerts. */ +"network.protection.vpn.alerts.toggle.section.footer" = "Get notified if your connection drops or VPN status changes."; + +/* Title for the toggle for VPN alerts. */ +"network.protection.vpn.alerts.toggle.title" = "VPN Alerts"; + /* Footer text for the Always on VPN setting item. */ "network.protection.vpn.always.on.setting.footer" = "Automatically restore a VPN connection after interruption."; diff --git a/PacketTunnelProvider/NetworkProtection/NetworkProtectionPacketTunnelProvider.swift b/PacketTunnelProvider/NetworkProtection/NetworkProtectionPacketTunnelProvider.swift index ccb15449ae..5db8d2c3c5 100644 --- a/PacketTunnelProvider/NetworkProtection/NetworkProtectionPacketTunnelProvider.swift +++ b/PacketTunnelProvider/NetworkProtection/NetworkProtectionPacketTunnelProvider.swift @@ -17,6 +17,8 @@ // limitations under the License. // +#if NETWORK_PROTECTION + import Foundation import NetworkProtection import Common @@ -167,8 +169,13 @@ final class NetworkProtectionPacketTunnelProvider: PacketTunnelProvider { errorEvents: nil) let errorStore = NetworkProtectionTunnelErrorStore() let notificationsPresenter = NetworkProtectionUNNotificationPresenter() + let notificationsSettingsStore = NetworkProtectionNotificationsSettingsUserDefaultsStore(userDefaults: .networkProtectionGroupDefaults) + let nofificationsPresenterDecorator = NetworkProtectionNotificationsPresenterTogglableDecorator( + notificationSettingsStore: notificationsSettingsStore, + wrappee: notificationsPresenter + ) notificationsPresenter.requestAuthorization() - super.init(notificationsPresenter: notificationsPresenter, + super.init(notificationsPresenter: nofificationsPresenterDecorator, tunnelHealthStore: NetworkProtectionTunnelHealthStore(), controllerErrorStore: errorStore, keychainType: .dataProtection(.unspecified), @@ -203,3 +210,5 @@ final class NetworkProtectionPacketTunnelProvider: PacketTunnelProvider { } } } + +#endif diff --git a/PacketTunnelProvider/PacketTunnelProvider.entitlements b/PacketTunnelProvider/PacketTunnelProvider.entitlements index 86c503b63c..5e171bb76b 100644 --- a/PacketTunnelProvider/PacketTunnelProvider.entitlements +++ b/PacketTunnelProvider/PacketTunnelProvider.entitlements @@ -9,6 +9,7 @@ com.apple.security.application-groups $(GROUP_ID_PREFIX).apptp + $(GROUP_ID_PREFIX).netp From 4dd122baf151286db73d003b1f8eb91eef75ba3a Mon Sep 17 00:00:00 2001 From: Elle Sullivan Date: Tue, 31 Oct 2023 18:10:28 +0000 Subject: [PATCH 7/7] Release 7.95.0 (#2122) --- Configuration/Version.xcconfig | 2 +- .../AppPrivacyConfigurationDataProvider.swift | 4 +- Core/ios-config.json | 578 +++++++++--------- DuckDuckGo.xcodeproj/project.pbxproj | 42 +- DuckDuckGo/Settings.bundle/Root.plist | 2 +- fastlane/metadata/default/release_notes.txt | 2 +- 6 files changed, 300 insertions(+), 330 deletions(-) diff --git a/Configuration/Version.xcconfig b/Configuration/Version.xcconfig index 13569f4d38..f1e581c2e5 100644 --- a/Configuration/Version.xcconfig +++ b/Configuration/Version.xcconfig @@ -1 +1 @@ -MARKETING_VERSION = 7.94.0 +MARKETING_VERSION = 7.95.0 diff --git a/Core/AppPrivacyConfigurationDataProvider.swift b/Core/AppPrivacyConfigurationDataProvider.swift index 1bb935f009..1c31465803 100644 --- a/Core/AppPrivacyConfigurationDataProvider.swift +++ b/Core/AppPrivacyConfigurationDataProvider.swift @@ -23,8 +23,8 @@ import BrowserServicesKit final public class AppPrivacyConfigurationDataProvider: EmbeddedDataProvider { public struct Constants { - public static let embeddedDataETag = "\"34b6806ec63c85144adb71af7e899b40\"" - public static let embeddedDataSHA = "167fdf9054fd7a0f8b2e9b5f84a8dae7d569752b0278d82b6a394380531f61e5" + public static let embeddedDataETag = "\"a0d037f309e88ecd0b730418db6d73c5\"" + public static let embeddedDataSHA = "9fc440e5eb590195150839759a56b34dd91cd5d11c84867526467362b7da08e7" } public var embeddedDataEtag: String { diff --git a/Core/ios-config.json b/Core/ios-config.json index 6c63a428f3..2cf867b907 100644 --- a/Core/ios-config.json +++ b/Core/ios-config.json @@ -1,6 +1,6 @@ { "readme": "https://github.com/duckduckgo/privacy-configuration", - "version": 1697654992169, + "version": 1698745071843, "features": { "adClickAttribution": { "readme": "https://help.duckduckgo.com/duckduckgo-help-pages/privacy/web-tracking-protections/#3rd-party-tracker-loading-protection", @@ -85,10 +85,6 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ], "settings": { @@ -114,7 +110,12 @@ ] }, "state": "enabled", - "hash": "cf1e1726876b6f6510eae65e2bc37047" + "hash": "c4367cb8ce342c06a089afa2bf8a7b84" + }, + "androidBrowserConfig": { + "exceptions": [], + "state": "disabled", + "hash": "728493ef7a1488e4781656d3f9db84aa" }, "autoconsent": { "exceptions": [ @@ -289,10 +290,6 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ], "settings": { @@ -301,7 +298,7 @@ ] }, "state": "enabled", - "hash": "6b201ccc9308a1e9b574b8a7da5a9b52" + "hash": "faab10f2de9c911fe8632c12dcfd52f5" }, "autofill": { "exceptions": [ @@ -343,12 +340,15 @@ "steps": [ { "percent": 1 + }, + { + "percent": 10 } ] } } }, - "hash": "555acbcb681d4f9b342dd2539c8e2c40" + "hash": "3a139910043488682718a3908993f8d3" }, "clickToLoad": { "exceptions": [ @@ -1163,10 +1163,6 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ], "settings": { @@ -1184,7 +1180,7 @@ } }, "state": "disabled", - "hash": "282361b69a7a17fbd3a6c53cdfba6b97" + "hash": "0348b68a4f222f86bb690dba5a230bed" }, "clickToPlay": { "exceptions": [ @@ -1199,10 +1195,6 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ], "settings": { @@ -1215,7 +1207,7 @@ } }, "state": "disabled", - "hash": "849beddfafbff071cd4a08697c265a38" + "hash": "41113a821c203f193f59b74df66c29a3" }, "contentBlocking": { "state": "enabled", @@ -1240,6 +1232,10 @@ "domain": "ads.google.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1401" }, + { + "domain": "sundancecatalog.com", + "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1420" + }, { "domain": "earth.google.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1099" @@ -1251,13 +1247,9 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ], - "hash": "f94b331bc97d678adbd90ed74feb40b2" + "hash": "f7cc238fd4b1655cfcfb8d4a72a88d03" }, "cookie": { "settings": { @@ -1310,18 +1302,14 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ], "state": "disabled", - "hash": "ee691572b20893705632f670a2f72801" + "hash": "a25d857f1b17af5e17c11eae8bb4c3b2" }, "customUserAgent": { "settings": { - "defaultPolicy": "ddg", + "defaultPolicy": "ddgFixed", "ddgFixedSites": [], "ddgDefaultSites": [ { @@ -1329,131 +1317,131 @@ "reason": "Internal exclusion to roll out experiment" } ], - "ddgFixedUserAgent": { + "closestUserAgent": { "versions": [ - "391", - "389", - "388", - "386", - "383", - "382", - "379", - "377", - "376", - "374", - "371", - "370", - "367", - "365", - "364", - "361", - "360", - "358", - "356", - "353", - "351", - "349", - "348", - "345", - "343", - "341", - "340", - "338", - "336", - "334", - "332", - "330", - "327", - "325", - "324", - "322", - "319", - "317", - "316", - "314", - "311", - "310", - "307", - "305", - "303", - "301", - "299", - "297", - "296", - "294", - "292", - "290", - "288", - "286", - "283", - "282", - "280", - "277", - "275", - "273", - "272", - "270", - "267", - "265", - "264", - "261", - "259", - "258", - "255", - "253", - "252", - "250", - "247", - "246", - "243", - "242", - "240", - "237", - "235", - "233", - "231", - "229", - "227", - "225", - "224", - "221", - "219", - "217", - "216", - "214", - "212", - "210", - "207", - "206", - "204", - "201", - "200", - "198", - "195", - "193", - "192", - "189", - "188", - "186", - "183", - "181", - "179", - "177", - "175", - "174", - "172", - "170", - "168", - "166", - "164", - "162", - "159", - "158", - "156", - "153", - "151", - "149", - "147" + "392", + "390", + "387", + "385", + "384", + "381", + "380", + "378", + "375", + "373", + "372", + "369", + "368", + "366", + "363", + "362", + "359", + "357", + "355", + "354", + "352", + "350", + "347", + "346", + "344", + "342", + "339", + "337", + "335", + "333", + "331", + "329", + "328", + "326", + "323", + "321", + "320", + "318", + "315", + "313", + "312", + "309", + "308", + "306", + "304", + "302", + "300", + "298", + "295", + "293", + "291", + "289", + "287", + "285", + "284", + "281", + "279", + "278", + "276", + "274", + "271", + "269", + "268", + "266", + "263", + "262", + "260", + "257", + "256", + "254", + "251", + "249", + "248", + "245", + "244", + "241", + "239", + "238", + "236", + "234", + "232", + "230", + "228", + "226", + "223", + "222", + "220", + "218", + "215", + "213", + "211", + "209", + "208", + "205", + "203", + "202", + "199", + "197", + "196", + "194", + "191", + "190", + "187", + "185", + "184", + "182", + "180", + "178", + "176", + "173", + "171", + "169", + "167", + "165", + "163", + "161", + "160", + "157", + "155", + "154", + "152", + "150", + "148" ] }, "omitApplicationSites": [ @@ -1509,10 +1497,6 @@ "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" - }, { "domain": "cvs.com", "reason": "Navigation section at the top of the main page renders as text." @@ -1521,6 +1505,10 @@ "domain": "facebook.com", "reason": "When going to the main login page, there is a banner at the top which warns of an 'Unsupported browser'." }, + { + "domain": "formula1.com", + "reason": "Stream page shows 'unsupported browser'" + }, { "domain": "hulu.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1145" @@ -1566,16 +1554,12 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ] }, "exceptions": [], "state": "enabled", - "hash": "10c9207834e45150fb4fa54cc22a9b92" + "hash": "2cb1f5495863943f82cb660836d9d844" }, "duckPlayer": { "exceptions": [], @@ -1732,10 +1716,6 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ], "settings": { @@ -2194,6 +2174,15 @@ } ] }, + { + "domain": "avito.ru", + "rules": [ + { + "selector": "[class*='advert-mimicry-block']", + "type": "hide" + } + ] + }, { "domain": "bbc.com", "rules": [ @@ -2335,15 +2324,6 @@ } ] }, - { - "domain": "dallasnews.com", - "rules": [ - { - "selector": "[data-targeting]", - "type": "hide-empty" - } - ] - }, { "domain": "dallasnews.com", "rules": [ @@ -2365,6 +2345,15 @@ } ] }, + { + "domain": "deseret.com", + "rules": [ + { + "selector": "[data-targeting]", + "type": "override" + } + ] + }, { "domain": "ebay.com", "rules": [ @@ -3414,6 +3403,15 @@ } ] }, + { + "domain": "whitakerfuneralhome.com", + "rules": [ + { + "selector": ".top-banner", + "type": "override" + } + ] + }, { "domain": "winnipegfreepress.com", "rules": [ @@ -3581,7 +3579,7 @@ ] }, "state": "enabled", - "hash": "b14a407a0c2cb050996646dfaadaf2db" + "hash": "acd3ac81772327d9018204dd0e268b28" }, "exceptionHandler": { "exceptions": [ @@ -3596,18 +3594,18 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ], "state": "disabled", - "hash": "f3fcace884f1423ec9c111587966d0bb" + "hash": "4cf9d85cdd66d5b30776fb9a38f8e143" }, "fingerprintingAudio": { "state": "disabled", "exceptions": [ + { + "domain": "litebluesso.usps.gov", + "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1424" + }, { "domain": "earth.google.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1099" @@ -3619,16 +3617,16 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ], - "hash": "47ea2125485511e0d94a8e767b246068" + "hash": "39522240455c067b38ce044b9c24d946" }, "fingerprintingBattery": { "exceptions": [ + { + "domain": "litebluesso.usps.gov", + "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1424" + }, { "domain": "earth.google.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1099" @@ -3640,14 +3638,10 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ], "state": "enabled", - "hash": "0f48731cc79a1d8d063df9f955f6acd4" + "hash": "0cb72d321c9503d7601ab0d94c0f0ac5" }, "fingerprintingCanvas": { "settings": { @@ -3710,6 +3704,10 @@ "domain": "ikea.com", "reason": "When creating an account, after filling out details and going to e-mail confirmation, there is an error 'Something went wrong', and the e-mail may not be received. Clicking 'Send new code' appears successful, but after entering the code there is often another account creation error." }, + { + "domain": "litebluesso.usps.gov", + "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1424" + }, { "domain": "manulife.ca", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/499" @@ -3773,14 +3771,10 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ], "state": "disabled", - "hash": "3b3d0307a60663097a8efad33af4fd08" + "hash": "464e5cecb38baef8eea5f747f44024c9" }, "fingerprintingHardware": { "settings": { @@ -3812,6 +3806,10 @@ "domain": "fedex.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/927" }, + { + "domain": "litebluesso.usps.gov", + "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1424" + }, { "domain": "realestate.com.au", "reason": "Site loads blank and does not proceed." @@ -3835,14 +3833,10 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ], "state": "enabled", - "hash": "c2469977eaaaf117362492d2c993fd1c" + "hash": "34d0e8f5460664b2cc2664ae47336165" }, "fingerprintingScreenSize": { "settings": { @@ -3880,6 +3874,10 @@ "domain": "hyatt.com", "reason": "Site loads blank and does not proceed." }, + { + "domain": "litebluesso.usps.gov", + "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1424" + }, { "domain": "secureserver.net", "reason": "After entering login details and clicking to log in, the site shows an adwall and prevents login." @@ -3895,14 +3893,10 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ], "state": "enabled", - "hash": "27afff6e74517f41184f4d3df479c53b" + "hash": "cbb7ca3551b6cfc219d228ef18a21130" }, "fingerprintingTemporaryStorage": { "exceptions": [ @@ -3910,6 +3904,10 @@ "domain": "fedex.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/927" }, + { + "domain": "litebluesso.usps.gov", + "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1424" + }, { "domain": "earth.google.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1099" @@ -3921,14 +3919,10 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ], "state": "enabled", - "hash": "4d9f5564b76c44f76b90692d98230d78" + "hash": "5726f4a4e6b435744db0a0ebc857994b" }, "googleRejected": { "exceptions": [ @@ -3943,14 +3937,10 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ], "state": "disabled", - "hash": "f3fcace884f1423ec9c111587966d0bb" + "hash": "4cf9d85cdd66d5b30776fb9a38f8e143" }, "gpc": { "state": "enabled", @@ -3967,6 +3957,10 @@ "domain": "costco.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/644" }, + { + "domain": "crunchyroll.com", + "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1422" + }, { "domain": "eventbrite.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/700" @@ -3994,10 +3988,6 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ], "settings": { @@ -4009,7 +3999,7 @@ "privacy-test-pages.site" ] }, - "hash": "402a82434b6f2b8a5321d9f004a7c33f" + "hash": "f3b1e7807c9b00ee721177ff8b9f1cd5" }, "harmfulApis": { "settings": { @@ -4122,14 +4112,10 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ], "state": "disabled", - "hash": "0381a7afb0f7453acb315ab3e0884eaa" + "hash": "bbc5332342823cf86f7f29b5760e80ce" }, "https": { "state": "enabled", @@ -4157,13 +4143,9 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ], - "hash": "2b7a26bbc23127a7ce24cc992066ad14" + "hash": "a4ed93a164b497b850ee1b4b337edcf3" }, "incontextSignup": { "exceptions": [], @@ -4204,10 +4186,6 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ], "settings": { @@ -4218,7 +4196,7 @@ ] }, "state": "enabled", - "hash": "002c32fcc15897c2ffae8045ac0bdcb3" + "hash": "6562f7d3e2dfb60604a0d56e5fe19ff2" }, "networkProtection": { "state": "disabled", @@ -4254,14 +4232,10 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ], "state": "disabled", - "hash": "81f357de4bfc7abeddf1a3a3fb1fc7a9" + "hash": "6e117549e8a40b811250fdb77f754e0c" }, "privacyDashboard": { "exceptions": [], @@ -4313,14 +4287,10 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ], "state": "disabled", - "hash": "6fb4590e0f11214e27a5386f24f1962f" + "hash": "f152d124dcf50f00bc8b5afd6d8cbe2e" }, "requestFilterer": { "state": "disabled", @@ -4336,16 +4306,12 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ], "settings": { "windowInMs": 0 }, - "hash": "c208c59a304e1d48cdd9ba85c0c8db25" + "hash": "ba2e7ce6c57f20ab022180ff29e013c4" }, "runtimeChecks": { "state": "disabled", @@ -4361,14 +4327,10 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ], "settings": {}, - "hash": "ca5b15f5db8334f68f29726b21d09c4a" + "hash": "fa49d2d969e1924b894c4b411a7c7430" }, "serviceworkerInitiatedRequests": { "exceptions": [ @@ -4383,14 +4345,10 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ], "state": "disabled", - "hash": "f3fcace884f1423ec9c111587966d0bb" + "hash": "4cf9d85cdd66d5b30776fb9a38f8e143" }, "trackerAllowlist": { "state": "enabled", @@ -4519,6 +4477,17 @@ } ] }, + "adswizz.com": { + "rules": [ + { + "rule": "synchrobox.adswizz.com", + "domains": [ + "tunein.com" + ], + "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1438" + } + ] + }, "adthrive.com": { "rules": [ { @@ -5233,14 +5202,6 @@ ], "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1107" }, - { - "rule": "alicdn.com.edgekey.net/", - "domains": [ - "aliexpress.com", - "aliexpress.us" - ], - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/570" - }, { "rule": "nintendo.com.edgekey.net/account/js/common.js", "domains": [ @@ -5496,7 +5457,7 @@ { "rule": "geoip-js.com/js/apis/geoip2/v2.1/geoip2.js", "domains": [ - "yourrewardcard.com" + "" ], "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1288" } @@ -5850,6 +5811,17 @@ } ] }, + "groovehq.com": { + "rules": [ + { + "rule": "widget.cluster.groovehq.com/_next/static/chunks/", + "domains": [ + "" + ], + "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1416" + } + ] + }, "gstatic.com": { "rules": [ { @@ -6399,6 +6371,17 @@ } ] }, + "permutive.app": { + "rules": [ + { + "rule": "edge.permutive.app", + "domains": [ + "globaltv.com" + ], + "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1418" + } + ] + }, "plotrabbit.com": { "rules": [ { @@ -6895,6 +6878,17 @@ } ] }, + "tiktok.com": { + "rules": [ + { + "rule": "www.tiktok.com/embed", + "domains": [ + "" + ], + "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1412" + } + ] + }, "tiqcdn.com": { "rules": [ { @@ -7263,13 +7257,9 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ], - "hash": "8cae71738e23bfd2e355653290f048b4" + "hash": "36405289e6da5cb590b78d1761d21ad7" }, "trackingCookies1p": { "settings": { @@ -7290,14 +7280,10 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ], "state": "disabled", - "hash": "0bea41340334fc80820a598f8b892e30" + "hash": "9eb0c864f68329c5c98269b9d77fce94" }, "trackingCookies3p": { "settings": { @@ -7315,14 +7301,10 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ], "state": "disabled", - "hash": "81f357de4bfc7abeddf1a3a3fb1fc7a9" + "hash": "6e117549e8a40b811250fdb77f754e0c" }, "trackingParameters": { "exceptions": [ @@ -7338,10 +7320,6 @@ "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" - }, { "domain": "theverge.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1326" @@ -7377,7 +7355,7 @@ ] }, "state": "enabled", - "hash": "aab19f2fd45ded0765912ee266c309df" + "hash": "cce5a16256c1522d32184562787a0ad7" }, "userAgentRotation": { "settings": { @@ -7395,14 +7373,10 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ], "state": "disabled", - "hash": "9775f6a60d1271671e6ef7a7cd2811be" + "hash": "158b0b3e010b8606819c6bc60c435805" }, "voiceSearch": { "exceptions": [], @@ -7422,10 +7396,6 @@ { "domain": "marvel.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1194" - }, - { - "domain": "paramountplus.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1085" } ], "state": "enabled", @@ -7458,7 +7428,7 @@ } ] }, - "hash": "40742df45658ad78c016f5a99178482d" + "hash": "c570e5c5011cf4cffbc62e7587a9731b" }, "windowsPermissionUsage": { "exceptions": [], diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index a18515068d..b125805159 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -7627,7 +7627,7 @@ CODE_SIGN_ENTITLEMENTS = PacketTunnelProvider/PacketTunnelProvider.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -7664,7 +7664,7 @@ CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -7756,7 +7756,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = ShareExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -7783,7 +7783,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -7929,7 +7929,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGo.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -7953,7 +7953,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGo.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; INFOPLIST_FILE = DuckDuckGo/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -8017,7 +8017,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEAD_CODE_STRIPPING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = Widgets/Info.plist; @@ -8052,7 +8052,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEAD_CODE_STRIPPING = NO; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -8086,7 +8086,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = OpenAction/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -8116,7 +8116,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -8402,7 +8402,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGoAlpha.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -8428,7 +8428,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -8460,7 +8460,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -8497,7 +8497,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEAD_CODE_STRIPPING = NO; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -8533,7 +8533,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -8568,11 +8568,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 2; + DYLIB_CURRENT_VERSION = 0; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -8746,11 +8746,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 2; + DYLIB_CURRENT_VERSION = 0; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -8779,10 +8779,10 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 2; + DYLIB_CURRENT_VERSION = 0; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; diff --git a/DuckDuckGo/Settings.bundle/Root.plist b/DuckDuckGo/Settings.bundle/Root.plist index a8d0320dbc..5efa0aff1d 100644 --- a/DuckDuckGo/Settings.bundle/Root.plist +++ b/DuckDuckGo/Settings.bundle/Root.plist @@ -6,7 +6,7 @@ DefaultValue - 7.94.0 + 7.95.0 Key version Title diff --git a/fastlane/metadata/default/release_notes.txt b/fastlane/metadata/default/release_notes.txt index 4942898476..35bc242613 100644 --- a/fastlane/metadata/default/release_notes.txt +++ b/fastlane/metadata/default/release_notes.txt @@ -1,3 +1,3 @@ -Bug fixes and other improvements. +You can now move the URL bar to the bottom of the screen by changing the location in App settings. Join our fully distributed team and help raise the standard of trust online! https://duckduckgo.com/hiring