Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Removes VPN waitlist and beta code #801

Merged
merged 16 commits into from
May 24, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,8 @@
import Foundation
import Common

public protocol NetworkProtectionCodeRedeeming {

/// Redeems an invite code with the Network Protection backend and stores the resulting auth token
func redeem(_ code: String) async throws

}

/// Coordinates calls to the backend and oAuth token storage
public final class NetworkProtectionCodeRedemptionCoordinator: NetworkProtectionCodeRedeeming {
public final class NetworkProtectionCodeRedemptionCoordinator {
private let networkClient: NetworkProtectionClient
private let tokenStore: NetworkProtectionTokenStore
private let isManualCodeRedemptionFlow: Bool
Expand All @@ -54,21 +47,4 @@ public final class NetworkProtectionCodeRedemptionCoordinator: NetworkProtection
self.errorEvents = errorEvents
}

public func redeem(_ code: String) async throws {
let result = await networkClient.redeem(inviteCode: code)
switch result {
case .success(let token):
try tokenStore.store(token)

case .failure(let error):
if case .invalidInviteCode = error, isManualCodeRedemptionFlow {
// Deliberately ignore cases where invalid invite codes are entered into the redemption form
throw error
} else {
errorEvents.fire(error.networkProtectionError)
throw error
}
}
}

}
10 changes: 0 additions & 10 deletions Sources/NetworkProtection/Networking/NetworkProtectionClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import Foundation

protocol NetworkProtectionClient {
func redeem(inviteCode: String) async -> Result<String, NetworkProtectionClientError>
func getLocations(authToken: String) async -> Result<[NetworkProtectionLocation], NetworkProtectionClientError>
func getServers(authToken: String) async -> Result<[NetworkProtectionServer], NetworkProtectionClientError>
func register(authToken: String,
Expand Down Expand Up @@ -189,10 +188,6 @@ final class NetworkProtectionBackendClient: NetworkProtectionClient {
endpointURL.appending("/register")
}

var redeemURL: URL {
endpointURL.appending("/redeem")
}

private let decoder: JSONDecoder = {
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withFullDate, .withFullTime, .withFractionalSeconds]
Expand Down Expand Up @@ -381,11 +376,6 @@ final class NetworkProtectionBackendClient: NetworkProtectionClient {
}
}

public func redeem(inviteCode: String) async -> Result<String, NetworkProtectionClientError> {
let requestBody = RedeemInviteCodeRequestBody(code: inviteCode)
return await retrieveAuthToken(requestBody: requestBody, endpoint: redeemURL)
}

private func retrieveAuthToken<RequestBody: Encodable>(
requestBody: RequestBody,
endpoint: URL
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,24 +85,3 @@ extension UserDefaults {
public extension Notification.Name {
static let vpnEntitlementMessagingDidChange = Notification.Name("com.duckduckgo.network-protection.entitlement-messaging-changed")
}

extension UserDefaults {
private var vpnEarlyAccessOverAlertAlreadyShownKey: String {
"vpnEarlyAccessOverAlertAlreadyShown"
}

@objc
public dynamic var vpnEarlyAccessOverAlertAlreadyShown: Bool {
get {
value(forKey: vpnEarlyAccessOverAlertAlreadyShownKey) as? Bool ?? false
}

set {
set(newValue, forKey: vpnEarlyAccessOverAlertAlreadyShownKey)
}
}

public func resetThankYouMessaging() {
removeObject(forKey: vpnEarlyAccessOverAlertAlreadyShownKey)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ private enum AttributesKey: String, CaseIterable {
case favorites
case appTheme
case daysSinceInstalled
case isNetPWaitlistUser
case daysSinceNetPEnabled

func matchingAttribute(jsonMatchingAttribute: AnyDecodable) -> MatchingAttribute {
Expand All @@ -56,7 +55,6 @@ private enum AttributesKey: String, CaseIterable {
case .favorites: return FavoritesMatchingAttribute(jsonMatchingAttribute: jsonMatchingAttribute)
case .appTheme: return AppThemeMatchingAttribute(jsonMatchingAttribute: jsonMatchingAttribute)
case .daysSinceInstalled: return DaysSinceInstalledMatchingAttribute(jsonMatchingAttribute: jsonMatchingAttribute)
case .isNetPWaitlistUser: return IsNetPWaitlistUserMatchingAttribute(jsonMatchingAttribute: jsonMatchingAttribute)
case .daysSinceNetPEnabled: return DaysSinceNetPEnabledMatchingAttribute(jsonMatchingAttribute: jsonMatchingAttribute)
}
}
Expand Down
11 changes: 1 addition & 10 deletions Sources/RemoteMessaging/Matchers/UserAttributeMatcher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ public struct UserAttributeMatcher: AttributeMatcher {
private let bookmarksCount: Int
private let favoritesCount: Int
private let isWidgetInstalled: Bool
private let isNetPWaitlistUser: Bool
private let daysSinceNetPEnabled: Int

public init(statisticsStore: StatisticsStore,
Expand All @@ -39,7 +38,6 @@ public struct UserAttributeMatcher: AttributeMatcher {
favoritesCount: Int,
appTheme: String,
isWidgetInstalled: Bool,
isNetPWaitlistUser: Bool,
daysSinceNetPEnabled: Int
) {
self.statisticsStore = statisticsStore
Expand All @@ -49,11 +47,10 @@ public struct UserAttributeMatcher: AttributeMatcher {
self.bookmarksCount = bookmarksCount
self.favoritesCount = favoritesCount
self.isWidgetInstalled = isWidgetInstalled
self.isNetPWaitlistUser = isNetPWaitlistUser
self.daysSinceNetPEnabled = daysSinceNetPEnabled
}

// swiftlint:disable:next cyclomatic_complexity function_body_length
// swiftlint:disable:next cyclomatic_complexity
func evaluate(matchingAttribute: MatchingAttribute) -> EvaluationResult? {
switch matchingAttribute {
case let matchingAttribute as AppThemeMatchingAttribute:
Expand Down Expand Up @@ -97,12 +94,6 @@ public struct UserAttributeMatcher: AttributeMatcher {
}

return BooleanMatchingAttribute(value).matches(value: isWidgetInstalled)
case let matchingAttribute as IsNetPWaitlistUserMatchingAttribute:
guard let value = matchingAttribute.value else {
return .fail
}

return BooleanMatchingAttribute(value).matches(value: isNetPWaitlistUser)
case let matchingAttribute as DaysSinceNetPEnabledMatchingAttribute:
if matchingAttribute.value != MatchingAttributeDefaults.intDefaultValue {
return IntMatchingAttribute(matchingAttribute.value).matches(value: daysSinceNetPEnabled)
Expand Down
25 changes: 0 additions & 25 deletions Sources/RemoteMessaging/Model/MatchingAttributes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -608,31 +608,6 @@ struct RangeStringNumericMatchingAttribute: Equatable {
}
}

struct IsNetPWaitlistUserMatchingAttribute: MatchingAttribute, Equatable {
var value: Bool?
var fallback: Bool?

init(jsonMatchingAttribute: AnyDecodable) {
guard let jsonMatchingAttribute = jsonMatchingAttribute.value as? [String: Any] else { return }

if let value = jsonMatchingAttribute[RuleAttributes.value] as? Bool {
self.value = value
}
if let fallback = jsonMatchingAttribute[RuleAttributes.fallback] as? Bool {
self.fallback = fallback
}
}

init(value: Bool?, fallback: Bool?) {
self.value = value
self.fallback = fallback
}

static func == (lhs: IsNetPWaitlistUserMatchingAttribute, rhs: IsNetPWaitlistUserMatchingAttribute) -> Bool {
return lhs.value == rhs.value && lhs.fallback == rhs.fallback
}
}

struct DaysSinceNetPEnabledMatchingAttribute: MatchingAttribute, Equatable {
var min: Int = MatchingAttributeDefaults.intDefaultValue
var max: Int = MatchingAttributeDefaults.intDefaultMaxValue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,14 +127,10 @@

let rule8 = config.rules.filter { $0.key == 8 }.first
XCTAssertNotNil(rule8)
XCTAssertTrue(rule8?.value.count == 2)

Check failure on line 130 in Tests/BrowserServicesKitTests/RemoteMessaging/Mappers/JsonToRemoteConfigModelMapperTests.swift

View workflow job for this annotation

GitHub Actions / Run unit tests (macOS)

testWhenValidJsonParsedThenRulesMappedIntoRemoteConfig, XCTAssertTrue failed

Check failure on line 130 in Tests/BrowserServicesKitTests/RemoteMessaging/Mappers/JsonToRemoteConfigModelMapperTests.swift

View workflow job for this annotation

GitHub Actions / Run unit tests (iOS)

testWhenValidJsonParsedThenRulesMappedIntoRemoteConfig, XCTAssertTrue failed
attribs = rule8?.value.filter { $0 is DaysSinceNetPEnabledMatchingAttribute }
XCTAssertEqual(attribs?.count, 1)
XCTAssertEqual(attribs?.first as? DaysSinceNetPEnabledMatchingAttribute, DaysSinceNetPEnabledMatchingAttribute(min: 5, fallback: nil))

attribs = rule8?.value.filter { $0 is IsNetPWaitlistUserMatchingAttribute }
XCTAssertEqual(attribs?.count, 1)
XCTAssertEqual(attribs?.first as? IsNetPWaitlistUserMatchingAttribute, IsNetPWaitlistUserMatchingAttribute(value: true, fallback: nil))
}

func testWhenJsonMessagesHaveUnknownTypesThenMessagesNotMappedIntoConfig() throws {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ class UserAttributeMatcherTests: XCTestCase {
favoritesCount: 88,
appTheme: "default",
isWidgetInstalled: true,
isNetPWaitlistUser: true,
daysSinceNetPEnabled: 3)
}

Expand Down Expand Up @@ -207,16 +206,6 @@ class UserAttributeMatcherTests: XCTestCase {

// MARK: - Network Protection Waitlist

func testWhenIsNetPWaitlistUserMatchesThenReturnMatch() throws {
XCTAssertEqual(userAttributeMatcher.evaluate(matchingAttribute: IsNetPWaitlistUserMatchingAttribute(value: true, fallback: nil)),
.match)
}

func testWhenIsNetPWaitlistUserDoesNotMatchThenReturnFail() throws {
XCTAssertEqual(userAttributeMatcher.evaluate(matchingAttribute: IsNetPWaitlistUserMatchingAttribute(value: false, fallback: nil)),
.fail)
}

func testWhenDaysSinceNetPEnabledMatchesThenReturnMatch() throws {
XCTAssertEqual(userAttributeMatcher.evaluate(matchingAttribute: DaysSinceNetPEnabledMatchingAttribute(min: 1, fallback: nil)),
.match)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ class RemoteMessagingConfigMatcherTests: XCTestCase {
favoritesCount: 0,
appTheme: "light",
isWidgetInstalled: false,
isNetPWaitlistUser: false,
daysSinceNetPEnabled: -1),
dismissedMessageIds: []
)
Expand Down Expand Up @@ -113,7 +112,6 @@ class RemoteMessagingConfigMatcherTests: XCTestCase {
favoritesCount: 0,
appTheme: "light",
isWidgetInstalled: false,
isNetPWaitlistUser: false,
daysSinceNetPEnabled: -1),
dismissedMessageIds: [])

Expand Down Expand Up @@ -182,7 +180,6 @@ class RemoteMessagingConfigMatcherTests: XCTestCase {
favoritesCount: 0,
appTheme: "light",
isWidgetInstalled: false,
isNetPWaitlistUser: false,
daysSinceNetPEnabled: -1),
dismissedMessageIds: ["1"])

Expand Down Expand Up @@ -212,7 +209,6 @@ class RemoteMessagingConfigMatcherTests: XCTestCase {
favoritesCount: 0,
appTheme: "light",
isWidgetInstalled: false,
isNetPWaitlistUser: false,
daysSinceNetPEnabled: -1),
dismissedMessageIds: [])

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ class RemoteMessagingConfigProcessorTests: XCTestCase {
favoritesCount: 0,
appTheme: "light",
isWidgetInstalled: false,
isNetPWaitlistUser: false,
daysSinceNetPEnabled: -1),
dismissedMessageIds: []
)
Expand Down Expand Up @@ -64,7 +63,6 @@ class RemoteMessagingConfigProcessorTests: XCTestCase {
favoritesCount: 0,
appTheme: "light",
isWidgetInstalled: false,
isNetPWaitlistUser: false,
daysSinceNetPEnabled: -1),
dismissedMessageIds: [])

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,9 +237,6 @@
{
"id": 8,
"attributes": {
"isNetPWaitlistUser": {
"value": true
},
samsymons marked this conversation as resolved.
Show resolved Hide resolved
"daysSinceNetPEnabled": {
"min": 5
}
Expand Down
71 changes: 4 additions & 67 deletions Tests/NetworkProtectionTests/NetworkProtectionClientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ final class NetworkProtectionClientTests: XCTestCase {

func testRegister401Response_ThrowsInvalidTokenError() async {
let emptyData = "".data(using: .utf8)!
MockURLProtocol.stubs[client.redeemURL] = (response: HTTPURLResponse(url: client.registerKeyURL, statusCode: 401)!,
MockURLProtocol.stubs[client.registerKeyURL] = (response: HTTPURLResponse(url: client.registerKeyURL, statusCode: 401)!,
.success(emptyData))

let body = RegisterKeyRequestBody(publicKey: .testData, serverSelection: .server(name: "MockServer"))
Expand All @@ -68,7 +68,7 @@ final class NetworkProtectionClientTests: XCTestCase {

func testGetServer401Response_ThrowsInvalidTokenError() async {
let emptyData = "".data(using: .utf8)!
MockURLProtocol.stubs[client.redeemURL] = (response: HTTPURLResponse(url: client.serversURL, statusCode: 401)!,
MockURLProtocol.stubs[client.serversURL] = (response: HTTPURLResponse(url: client.serversURL, statusCode: 401)!,
.success(emptyData))

let result = await client.getServers(authToken: "anAuthToken")
Expand All @@ -79,74 +79,11 @@ final class NetworkProtectionClientTests: XCTestCase {
}
}

// MARK: redeem(inviteCode:)

func testRedeemSuccess() async {
let token = "a6s7ad6ad76aasa7s6a"
let successData = redeemSuccessData(token: token)
MockURLProtocol.stubs[client.redeemURL] = (response: HTTPURLResponse(url: client.redeemURL, statusCode: 200)!,
.success(successData))

let result = await client.redeem(inviteCode: "DH76F8S")

XCTAssertEqual(try? result.get(), token)
}

func testRedeem400Response() async {
let emptyData = "".data(using: .utf8)!
MockURLProtocol.stubs[client.redeemURL] = (response: HTTPURLResponse(url: client.redeemURL, statusCode: 400)!,
.success(emptyData))

let result = await client.redeem(inviteCode: "DH76F8S")

guard case .failure(let error) = result, case .invalidInviteCode = error else {
XCTFail("Expected an invalidInviteCode error to be thrown")
return
}
}

func testRedeemNon200Or400Response() async {
let emptyData = "".data(using: .utf8)!

for code in [401, 304, 500] {
MockURLProtocol.stubs[client.redeemURL] = (response: HTTPURLResponse(url: client.redeemURL, statusCode: code)!,
.success(emptyData))

let result = await client.redeem(inviteCode: "DH76F8S")

guard case .failure(let error) = result, case .failedToRedeemInviteCode = error else {
XCTFail("Expected a failedToRedeemInviteCode error to be thrown")
return
}
}
}

func testRedeemDecodeFailure() async {
let undecodableData = "sdfghj".data(using: .utf8)!
MockURLProtocol.stubs[client.redeemURL] = (response: HTTPURLResponse(url: client.redeemURL, statusCode: 200)!,
.success(undecodableData))

let result = await client.redeem(inviteCode: "DH76F8S")

guard case .failure(let error) = result, case .failedToParseRedeemResponse = error else {
XCTFail("Expected a failedToRedeemInviteCode error to be thrown")
return
}
}

private func redeemSuccessData(token: String) -> Data {
return """
{
"token": "\(token)"
}
""".data(using: .utf8)!
}

// MARK: locations(authToken:)

func testLocationsSuccess() async {
let successData = TestData.mockLocations
MockURLProtocol.stubs[client.locationsURL] = (response: HTTPURLResponse(url: client.redeemURL, statusCode: 200)!,
MockURLProtocol.stubs[client.locationsURL] = (response: HTTPURLResponse(url: client.locationsURL, statusCode: 200)!,
.success(successData))

let result = await client.getLocations(authToken: "DH76F8S")
Expand Down Expand Up @@ -185,7 +122,7 @@ final class NetworkProtectionClientTests: XCTestCase {

func testLocationsDecodeFailure() async {
let undecodableData = "sdfghj".data(using: .utf8)!
MockURLProtocol.stubs[client.locationsURL] = (response: HTTPURLResponse(url: client.redeemURL, statusCode: 200)!,
MockURLProtocol.stubs[client.locationsURL] = (response: HTTPURLResponse(url: client.locationsURL, statusCode: 200)!,
.success(undecodableData))

let result = await client.getLocations(authToken: "DH76F8S")
Expand Down
Loading