Skip to content

Commit

Permalink
Add proper error handling to VPN code so it throws an exception when …
Browse files Browse the repository at this point in the history
…something wrong happens instead of just returning null.
  • Loading branch information
Brandon-T committed Oct 25, 2024
1 parent 8476a91 commit 2be77b1
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 26 deletions.
15 changes: 9 additions & 6 deletions ios/brave-ios/Sources/BraveVPN/BraveVPN.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,15 @@ public class BraveVPN {
}

Task {
let receiptResponse = await validateReceiptData()
// Clear configuration if only if the receipt response is expired (not retryPeriod)
if receiptResponse?.status == .expired {
clearConfiguration()
logAndStoreError("Receipt expired")
return
do {
let receiptResponse = try await validateReceiptData()
// Clear configuration if only if the receipt response is expired (not retryPeriod)
if receiptResponse?.status == .expired {
clearConfiguration()
logAndStoreError("Receipt expired")
}
} catch {
logAndStoreError(String(describing: error))
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ extension BuyVPNViewController: BraveVPNInAppPurchaseObserverDelegate {

if validateReceipt {
Task {
_ = await BraveVPN.validateReceiptData()
_ = try await BraveVPN.validateReceiptData()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ extension BraveVPNSettingsViewController: BraveVPNInAppPurchaseObserverDelegate

if validateReceipt {
Task {
_ = await BraveVPN.validateReceiptData()
_ = try await BraveVPN.validateReceiptData()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,19 @@ import Preferences

extension BraveVPN {

public enum BraveVPNError: Error {
case noReceipt
case noReceiptData
case noReceiptStatus
case noReceiptExpiryDate
case noReceiptGraceExpiryDate
case noReceiptIsInTrialPeriod
case noReceiptAutoRenewEnabled
case noReceiptExpiryIntent
case noReceiptExpiryIntentUnknown
case noResponse
}

public struct ReceiptResponse {
public enum Status: Int {
case active, expired, retryPeriod
Expand Down Expand Up @@ -35,12 +48,12 @@ extension BraveVPN {
}

/// Connects to Guardian's server to validate locally stored receipt.
/// Returns ReceiptResponse whoich hold information about status of receipt expiration etc
public static func validateReceiptData() async -> ReceiptResponse? {
/// Returns ReceiptResponse which hold information about status of receipt expiration etc
public static func validateReceiptData() async throws -> ReceiptResponse? {
guard let receipt = await loadReceipt(),
let bundleId = Bundle.main.bundleIdentifier
else {
return nil
throw BraveVPNError.noReceipt
}

if Preferences.VPN.skusCredential.value != nil {
Expand All @@ -49,21 +62,21 @@ extension BraveVPN {
return nil
}

return await withCheckedContinuation { continuation in
return try await withCheckedThrowingContinuation { continuation in
housekeepingApi.verifyReceiptData(receipt, bundleId: bundleId) { response, error in
if let error = error {
// Error while fetching receipt response, the variations of error can be listed
// No App Store receipt data present
// Failed to retrieve receipt data from server
// Failed to decode JSON response data
logAndStoreError("Call for receipt verification failed: \(error.localizedDescription)")
continuation.resume(returning: nil)
continuation.resume(throwing: error)
return
}

guard let response = response else {
logAndStoreError("Receipt verification response is empty")
continuation.resume(returning: nil)
continuation.resume(throwing: BraveVPNError.noResponse)
return
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,18 +71,23 @@ public class BraveVPNInAppPurchaseObserver: NSObject, SKPaymentTransactionObserv
Preferences.VPN.subscriptionProductId.value = transaction.payment.productIdentifier

Task {
let response = await BraveVPN.validateReceiptData()
if response?.status == .expired {
// Receipt either expired or receipt validation returned some error.
self.delegate?.purchaseFailed(error: .receiptError)
} else {
self.delegate?.purchasedOrRestoredProduct(validateReceipt: false)
// If we purchased via Apple's IAP we reset the Brave SKUs credential
// to avoid mixing two purchase types in the app.
//
// The user will be able to retrieve the shared credential
// after log in to account.brave website.
BraveVPN.clearSkusCredentials(includeExpirationDate: false)
do {
let response = try await BraveVPN.validateReceiptData()
if response?.status == .expired {
// Receipt either expired or receipt validation returned some error.
self.delegate?.purchaseFailed(error: .receiptError)
} else {
self.delegate?.purchasedOrRestoredProduct(validateReceipt: false)
// If we purchased via Apple's IAP we reset the Brave SKUs credential
// to avoid mixing two purchase types in the app.
//
// The user will be able to retrieve the shared credential
// after log in to account.brave website.
BraveVPN.clearSkusCredentials(includeExpirationDate: false)
}
} catch {
Logger.module.error("Error validating receipt: \(error)")
self.delegate?.purchaseFailed(error: .transactionError(error: SKError(.unknown)))
}
}
}
Expand Down

0 comments on commit 2be77b1

Please sign in to comment.