Skip to content

Commit

Permalink
Merge branch 'main' into brindy/progress-bar-gradients
Browse files Browse the repository at this point in the history
  • Loading branch information
brindy committed Feb 1, 2024
2 parents fabfd30 + 930fce6 commit 2e68889
Show file tree
Hide file tree
Showing 202 changed files with 4,873 additions and 4,876 deletions.
6 changes: 1 addition & 5 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,7 @@ CC:
**Description**:

<!--
Tagging instructions
If this PR isn't ready to be merged for whatever reason it should be marked with the `DO NOT MERGE` label (particularly if it's a draft)
If it's pending Product Review/PFR, please add the `Pending Product Review` label.
If at any point it isn't actively being worked on/ready for review/otherwise moving forward (besides the above PR/PFR exception) strongly consider closing it (or not opening it in the first place). If you decide not to close it, make sure it's labelled to make it clear the PRs state and comment with more information.
If at any point it isn't actively being worked on/ready for review/otherwise moving forward strongly consider closing it (or not opening it in the first place). If you decide not to close it, use Draft PR while work is still in progress or use `DO NOT MERGE` label to clarify the PRs state and comment with more information.
-->

**Steps to test this PR**:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/end-to-end.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ jobs:
--header "Accept: application/json" \
--header "Authorization: Bearer ${{ secrets.ASANA_ACCESS_TOKEN }}" \
--header "Content-Type: application/json" \
--data ' { "data": { "name": "GH Workflow Failure - End to end tests", "workspace": "${{ vars.GH_ASANA_WORKSPACE_ID }}", "projects": [ "${{ vars.GH_ASANA_IOS_APP_PROJECT_ID }}" ], "notes" : "The end to end workflow has failed. See https://github.com/duckduckgo/iOS/actions/runs/${{ github.run_id }}" } }'
--data ' { "data": { "name": "GH Workflow Failure - End to end tests", "workspace": "${{ vars.GH_ASANA_WORKSPACE_ID }}", "projects": [ "${{ vars.GH_ASANA_IOS_APP_PROJECT_ID }}" ], "notes" : "The end to end workflow has failed. See https://github.com/duckduckgo/iOS/actions/runs/${{ github.run_id }}. For instructions on how to handle the failure(s), check https://app.asana.com/0/0/1206423571874502/f" } }'
- name: Upload logs when workflow failed
uses: actions/upload-artifact@v4
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ jobs:
run: |
set -o pipefail && xcodebuild test \
-scheme "AtbUITests" \
-destination "platform=iOS Simulator,name=iPhone 14,OS=16.4" \
-destination "platform=iOS Simulator,name=iPhone 15,OS=17.2" \
-derivedDataPath "DerivedData" \
-skipPackagePluginValidation \
| tee xcodebuild.log \
Expand Down Expand Up @@ -86,7 +86,7 @@ jobs:
run: |
set -o pipefail && xcodebuild test \
-scheme "FingerprintingUITests" \
-destination "platform=iOS Simulator,name=iPhone 14,OS=16.4" \
-destination "platform=iOS Simulator,name=iPhone 15,OS=17.2" \
-derivedDataPath "DerivedData" \
-skipPackagePluginValidation \
| xcbeautify --report junit --report-path . --junit-report-filename unittests.xml
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ jobs:

name: Make Release Build

# Dependabot doesn't have access to all secrets, so we skip this job
if: github.actor != 'dependabot[bot]'

runs-on: macos-13-xlarge
timeout-minutes: 30

Expand Down
6 changes: 2 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,13 @@ on:
branches:
- release/**
- hotfix/**
- coldfix/**
- '!release/**-' # filter out PRs matching that pattern
- '!hotfix/**-'
- '!coldfix/**-'
types: [closed]

jobs:
make-release:
if: github.event.action == 0 || github.event.pull_request.merged == true # empty string returns 0; for case when workflow is triggered manually
if: github.event.action == 0 || (github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'Merge triggers release')) # empty string returns 0; for case when workflow is triggered manually
runs-on: macos-13-xlarge
name: Make App Store Connect Release

Expand Down Expand Up @@ -98,7 +96,7 @@ jobs:
- name: Upload debug symbols to Asana
if: ${{ always() && github.event.inputs.asana-task-url }}
env:
env:
ASANA_ACCESS_TOKEN: ${{ secrets.ASANA_ACCESS_TOKEN }}
run: |
if [[ -f ${{ env.dsyms_path }} ]]; then
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,5 @@ fastlane/test_output

Configuration/ExternalDeveloper.xcconfig
scripts/assets

DuckDuckGoTests/NetworkProtectionVPNLocationViewModelTests.swift*.plist
4 changes: 3 additions & 1 deletion .maestro/release_tests/emailprotection.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ tags:
- scroll
- assertVisible: Email Protection
- tapOn: Email Protection
- assertVisible: Email privacy, simplified.
- assertVisible:
id: searchEntry
- tapOn:
id: "searchEntry"
- assertVisible: https://duckduckgo.com/email/
- assertVisible: Email privacy, simplified.
2 changes: 1 addition & 1 deletion Configuration/Version.xcconfig
Original file line number Diff line number Diff line change
@@ -1 +1 @@
MARKETING_VERSION = 7.105.0
MARKETING_VERSION = 7.107.0
4 changes: 2 additions & 2 deletions Core/AppPrivacyConfigurationDataProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ import BrowserServicesKit
final public class AppPrivacyConfigurationDataProvider: EmbeddedDataProvider {

public struct Constants {
public static let embeddedDataETag = "\"489ab3f1fc4e889123d6f51a4c0aefec\""
public static let embeddedDataSHA = "41adeed122f363b3ec2cd3ac189468bbe68b85b44e6a6ab342950561163cc263"
public static let embeddedDataETag = "\"d0ae514c42e1e632584aba7a025b8b92\""
public static let embeddedDataSHA = "b304a2dbb2edc7443a4950bb2ba9f7604354cf32575dd5a9ca09acd5c4b78146"
}

public var embeddedDataEtag: String {
Expand Down
86 changes: 78 additions & 8 deletions Core/CookieStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,27 @@ import Foundation

public class CookieStorage {

struct Constants {
static let key = "com.duckduckgo.allowedCookies"
struct Keys {
static let allowedCookies = "com.duckduckgo.allowedCookies"
static let consumed = "com.duckduckgo.consumedCookies"
}

private var userDefaults: UserDefaults


var isConsumed: Bool {
get {
userDefaults.bool(forKey: Keys.consumed, defaultValue: false)
}
set {
userDefaults.set(newValue, forKey: Keys.consumed)
}
}

/// Use the `updateCookies` function rather than the setter which is only visible for testing.
var cookies: [HTTPCookie] {
get {
var storedCookies = [HTTPCookie]()
if let cookies = userDefaults.object(forKey: Constants.key) as? [[String: Any?]] {
if let cookies = userDefaults.object(forKey: Keys.allowedCookies) as? [[String: Any?]] {
for cookieData in cookies {
var properties = [HTTPCookiePropertyKey: Any]()
cookieData.forEach({
Expand All @@ -57,17 +68,76 @@ public class CookieStorage {
}
cookies.append(mappedCookie)
}
userDefaults.setValue(cookies, forKey: Constants.key)
userDefaults.setValue(cookies, forKey: Keys.allowedCookies)
}

}

public init(userDefaults: UserDefaults = UserDefaults.app) {
self.userDefaults = userDefaults
}

func clear() {
userDefaults.removeObject(forKey: Constants.key)
os_log("cleared cookies", log: .generalLog, type: .debug)
enum CookieDomainsOnUpdate {
case empty
case match
case missing
case different
}

@discardableResult
func updateCookies(_ cookies: [HTTPCookie], keepingPreservedLogins preservedLogins: PreserveLogins) -> CookieDomainsOnUpdate {
isConsumed = false

let persisted = self.cookies

func cookiesByDomain(_ cookies: [HTTPCookie]) -> [String: [HTTPCookie]] {
var byDomain = [String: [HTTPCookie]]()
cookies.forEach { cookie in
var cookies = byDomain[cookie.domain, default: []]
cookies.append(cookie)
byDomain[cookie.domain] = cookies
}
return byDomain
}

let updatedCookiesByDomain = cookiesByDomain(cookies)
var persistedCookiesByDomain = cookiesByDomain(persisted)

// Do the diagnostics before the dicts get changed.
let diagnosticResult = evaluateDomains(
updatedDomains: updatedCookiesByDomain.keys.sorted(),
persistedDomains: persistedCookiesByDomain.keys.sorted()
)

updatedCookiesByDomain.keys.forEach {
persistedCookiesByDomain[$0] = updatedCookiesByDomain[$0]
}

persistedCookiesByDomain.keys.forEach {
guard $0 != "duckduckgo.com" else { return } // DDG cookies are for SERP settings only

if !preservedLogins.isAllowed(cookieDomain: $0) {
persistedCookiesByDomain.removeValue(forKey: $0)
}
}

let now = Date()
self.cookies = persistedCookiesByDomain.map { $0.value }.joined().compactMap { $0 }
.filter { $0.expiresDate == nil || $0.expiresDate! > now }

return diagnosticResult
}

private func evaluateDomains(updatedDomains: [String], persistedDomains: [String]) -> CookieDomainsOnUpdate {
if persistedDomains.isEmpty {
return .empty
} else if updatedDomains.count < persistedDomains.count {
return .missing
} else if updatedDomains == persistedDomains {
return .match
} else {
return .different
}
}

}
15 changes: 13 additions & 2 deletions Core/DailyPixel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,16 @@ public final class DailyPixel {
public static func fireDailyAndCount(pixel: Pixel.Event,
error: Swift.Error? = nil,
withAdditionalParameters params: [String: String] = [:],
includedParameters: [Pixel.QueryParameters] = [.atb, .appVersion],
onDailyComplete: @escaping (Swift.Error?) -> Void = { _ in },
onCountComplete: @escaping (Swift.Error?) -> Void = { _ in }) {
if !pixel.hasBeenFiredToday(dailyPixelStorage: storage) {
Pixel.fire(pixelNamed: pixel.name + "_d", withAdditionalParameters: params, onComplete: onDailyComplete)
Pixel.fire(
pixelNamed: pixel.name + "_d",
withAdditionalParameters: params,
includedParameters: includedParameters,
onComplete: onDailyComplete
)
} else {
onDailyComplete(Error.alreadyFired)
}
Expand All @@ -83,7 +89,12 @@ public final class DailyPixel {
if let error {
newParams.appendErrorPixelParams(error: error)
}
Pixel.fire(pixelNamed: pixel.name + "_c", withAdditionalParameters: newParams, onComplete: onCountComplete)
Pixel.fire(
pixelNamed: pixel.name + "_c",
withAdditionalParameters: newParams,
includedParameters: includedParameters,
onComplete: onCountComplete
)
}

private static func updatePixelLastFireDate(pixel: Pixel.Event) {
Expand Down
4 changes: 0 additions & 4 deletions Core/DefaultVariantManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,6 @@ 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: 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
]

Expand Down
4 changes: 2 additions & 2 deletions Core/FeatureFlag.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ public enum FeatureFlag: String {
case networkProtection
case networkProtectionWaitlistAccess
case networkProtectionWaitlistActive
case privacyPro
case subscription
}

extension FeatureFlag: FeatureFlagSourceProviding {
public var source: FeatureFlagSource {
switch self {
case .debugMenu, .appTrackingProtection, .privacyPro:
case .debugMenu, .appTrackingProtection, .subscription:
return .internalOnly
case .sync:
return .remoteReleasable(.subfeature(SyncSubfeature.level0ShowSync))
Expand Down
29 changes: 28 additions & 1 deletion Core/PixelEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ extension Pixel {

case appLaunch
case refreshPressed
case pullToRefresh

case forgetAllPressedBrowsing
case forgetAllPressedTabSwitching
Expand Down Expand Up @@ -280,6 +281,8 @@ extension Pixel {

case networkProtectionEnabledOnSearch

case networkProtectionBreakageReport

case networkProtectionRekeyCompleted

case networkProtectionTunnelConfigurationNoServerRegistrationInfo
Expand Down Expand Up @@ -309,6 +312,7 @@ extension Pixel {
case networkProtectionKeychainErrorFailedToCastKeychainValueToData
case networkProtectionKeychainReadError
case networkProtectionKeychainWriteError
case networkProtectionKeychainUpdateError
case networkProtectionKeychainDeleteError

case networkProtectionWireguardErrorCannotLocateTunnelFileDescriptor
Expand Down Expand Up @@ -338,6 +342,7 @@ extension Pixel {
case networkProtectionWaitlistTermsAccepted
case networkProtectionWaitlistNotificationShown
case networkProtectionWaitlistNotificationLaunched
case networkProtectionWaitlistRetriedInviteCodeRedemption

case networkProtectionGeoswitchingOpened
case networkProtectionGeoswitchingSetNearest
Expand Down Expand Up @@ -489,6 +494,13 @@ extension Pixel {
case syncCredentialsFailed
case syncSettingsFailed
case syncSettingsMetadataUpdateFailed
case syncSignupError
case syncLoginError
case syncLogoutError
case syncUpdateDeviceError
case syncRemoveDeviceError
case syncDeleteAccountError
case syncLoginExistingAccountError

case bookmarksCleanupFailed
case bookmarksCleanupAttemptedWhileSyncWasEnabled
Expand All @@ -511,6 +523,8 @@ extension Pixel {
case emailIncontextModalExitEarlyContinue

case compilationFailed

case appRatingPromptFetchError
}

}
Expand All @@ -523,7 +537,8 @@ extension Pixel.Event {
switch self {
case .appLaunch: return "ml"
case .refreshPressed: return "m_r"

case .pullToRefresh: return "m_pull-to-reload"

case .forgetAllPressedBrowsing: return "mf_bp"
case .forgetAllPressedTabSwitching: return "mf_tp"
case .forgetAllExecuted: return "mf"
Expand Down Expand Up @@ -771,6 +786,7 @@ extension Pixel.Event {
case .networkProtectionLatencyError: return "m_netp_ev_latency_error_d"
case .networkProtectionRekeyCompleted: return "m_netp_rekey_completed"
case .networkProtectionEnabledOnSearch: return "m_netp_ev_enabled_on_search"
case .networkProtectionBreakageReport: return "m_vpn_breakage_report"
case .networkProtectionTunnelConfigurationNoServerRegistrationInfo: return "m_netp_tunnel_config_error_no_server_registration_info"
case .networkProtectionTunnelConfigurationCouldNotSelectClosestServer: return "m_netp_tunnel_config_error_could_not_select_closest_server"
case .networkProtectionTunnelConfigurationCouldNotGetPeerPublicKey: return "m_netp_tunnel_config_error_could_not_get_peer_public_key"
Expand Down Expand Up @@ -798,6 +814,7 @@ extension Pixel.Event {
case .networkProtectionKeychainErrorFailedToCastKeychainValueToData: return "m_netp_keychain_error_failed_to_cast_keychain_value_to_data"
case .networkProtectionKeychainReadError: return "m_netp_keychain_error_read_failed"
case .networkProtectionKeychainWriteError: return "m_netp_keychain_error_write_failed"
case .networkProtectionKeychainUpdateError: return "m_netp_keychain_error_update_failed"
case .networkProtectionKeychainDeleteError: return "m_netp_keychain_error_delete_failed"
case .networkProtectionWireguardErrorCannotLocateTunnelFileDescriptor: return "m_netp_wireguard_error_cannot_locate_tunnel_file_descriptor"
case .networkProtectionWireguardErrorInvalidState: return "m_netp_wireguard_error_invalid_state"
Expand All @@ -821,6 +838,7 @@ extension Pixel.Event {
case .networkProtectionWaitlistTermsAccepted: return "m_netp_waitlist_terms_accepted"
case .networkProtectionWaitlistNotificationShown: return "m_netp_waitlist_notification_shown"
case .networkProtectionWaitlistNotificationLaunched: return "m_netp_waitlist_notification_launched"
case .networkProtectionWaitlistRetriedInviteCodeRedemption: return "m_netp_waitlist_retried_invite_code_redemption"

case .networkProtectionGeoswitchingOpened: return "m_netp_imp_geoswitching"
case .networkProtectionGeoswitchingSetNearest: return "m_netp_ev_geoswitching_set_nearest"
Expand Down Expand Up @@ -969,6 +987,13 @@ extension Pixel.Event {
case .syncCredentialsFailed: return "m_d_sync_credentials_failed"
case .syncSettingsFailed: return "m_d_sync_settings_failed"
case .syncSettingsMetadataUpdateFailed: return "m_d_sync_settings_metadata_update_failed"
case .syncSignupError: return "m_d_sync_signup_error"
case .syncLoginError: return "m_d_sync_login_error"
case .syncLogoutError: return "m_d_sync_logout_error"
case .syncUpdateDeviceError: return "m_d_sync_update_device_error"
case .syncRemoveDeviceError: return "m_d_sync_remove_device_error"
case .syncDeleteAccountError: return "m_d_sync_delete_account_error"
case .syncLoginExistingAccountError: return "m_d_sync_login_existing_account_error"


case .bookmarksCleanupFailed: return "m_d_bookmarks_cleanup_failed"
Expand Down Expand Up @@ -996,6 +1021,8 @@ extension Pixel.Event {
// MARK: - Return user measurement
case .debugReturnUserAddATB: return "m_debug_return_user_add_atb"
case .debugReturnUserUpdateATB: return "m_debug_return_user_update_atb"

case .appRatingPromptFetchError: return "m_d_app_rating_prompt_fetch_error"
}

}
Expand Down
Loading

0 comments on commit 2e68889

Please sign in to comment.