diff --git a/Package.resolved b/Package.resolved index 69ff4bf..d3548dd 100644 --- a/Package.resolved +++ b/Package.resolved @@ -6,8 +6,8 @@ "repositoryURL": "https://github.com/tikhop/ASN1Swift", "state": { "branch": null, - "revision": "0f3150de37d38190768caaff19c498d85efad715", - "version": "1.2.3" + "revision": "b53bee03a942623db25afc5bfb80227b2cb3b425", + "version": "1.2.4" } } ] diff --git a/Sources/Date+Extension.swift b/Sources/Date+Extension.swift index 3753d8b..93f6d30 100644 --- a/Sources/Date+Extension.swift +++ b/Sources/Date+Extension.swift @@ -18,24 +18,16 @@ public extension Date public extension String { - func utcTime() -> Date? - { - - let formatter = ISO8601DateFormatter() - formatter.timeZone = TimeZone(abbreviation: "UTC") - formatter.formatOptions = .withInternetDateTime - - let date = formatter.date(from: self) - return date - } - func rfc3339date() -> Date? { - let formatter = ISO8601DateFormatter() - formatter.formatOptions = .withInternetDateTime - formatter.timeZone = TimeZone(abbreviation: "UTC") - - let date = formatter.date(from: self) + let date = rfc3339DateFormater.date(from: self) return date } } + +fileprivate var rfc3339DateFormater: ISO8601DateFormatter = { + let formatter = ISO8601DateFormatter() + formatter.formatOptions = .withInternetDateTime + formatter.timeZone = TimeZone(abbreviation: "UTC") + return formatter +}() diff --git a/Sources/InAppPurchase.swift b/Sources/InAppPurchase.swift index 07ac50b..4801940 100644 --- a/Sources/InAppPurchase.swift +++ b/Sources/InAppPurchase.swift @@ -40,17 +40,17 @@ public struct InAppPurchase /// Original Transaction identifier public var originalTransactionIdentifier: String - /// Purchase Date in string format - public var purchaseDateString: String + /// Purchase Date + public var purchaseDate: Date - /// Original Purchase Date in string format - public var originalPurchaseDateString: String + /// Original Purchase Date + public var originalPurchaseDate: Date - /// Subscription Expiration Date in string format. Returns `nil` if the purchase is not a renewable subscription - public var subscriptionExpirationDateString: String? = nil + /// Subscription Expiration Date. Returns `nil` if the purchase has been expired (in some cases) + public var subscriptionExpirationDate: Date? = nil - /// Cancellation Date in string format. Returns `nil` if the purchase is not a renewable subscription - public var cancellationDateString: String? = nil + /// Cancellation Date. Returns `nil` if the purchase is not a renewable subscription + public var cancellationDate: Date? = nil /// This value is `true`if the customer’s subscription is currently in the free trial period, or `false` if not. public var subscriptionTrialPeriod: Bool = false @@ -68,37 +68,14 @@ public struct InAppPurchase /// The number of consumable products purchased /// The default value is `1` unless modified with a mutable payment. The maximum value is 10. public var quantity: Int = 1 - - public init() - { - originalTransactionIdentifier = "" - productIdentifier = "" - transactionIdentifier = "" - purchaseDateString = "" - originalPurchaseDateString = "" - } } public extension InAppPurchase { - /// Purchase Date representation as a 'Date' object - var purchaseDate: Date - { - return purchaseDateString.rfc3339date()! - } - - /// Subscription Expiration Date representation as a 'Date' object. Returns `nil` if the purchase has been expired (in some cases) - var subscriptionExpirationDate: Date? - { - assert(isRenewableSubscription, "\(productIdentifier) is not an auto-renewable subscription.") - - return subscriptionExpirationDateString?.rfc3339date() - } - /// A Boolean value indicating whether the purchase is renewable subscription. var isRenewableSubscription: Bool { - return self.subscriptionExpirationDateString != nil + return subscriptionExpirationDate != nil } /// Check whether the subscription is active for a specific date @@ -109,10 +86,10 @@ public extension InAppPurchase { assert(isRenewableSubscription, "\(productIdentifier) is not an auto-renewable subscription.") - if(self.cancellationDateString != nil && self.cancellationDateString != "") - { - return false - } + if cancellationDate != nil + { + return false + } guard let expirationDate = subscriptionExpirationDate else { diff --git a/Sources/InAppReceipt+ASN1Decodable.swift b/Sources/InAppReceipt+ASN1Decodable.swift index 274cf3e..36ee3ed 100644 --- a/Sources/InAppReceipt+ASN1Decodable.swift +++ b/Sources/InAppReceipt+ASN1Decodable.swift @@ -108,8 +108,8 @@ extension InAppReceiptPayload: ASN1Decodable var purchases = [InAppPurchase]() var opaqueValue = Data() var receiptHash = Data() - var expirationDate: String? = "" - var receiptCreationDate: String = "" + var expirationDate: Date? + var receiptCreationDate: Date! var environment: String = "" let c = try decoder.container(keyedBy: CodingKeys.self) @@ -140,9 +140,11 @@ extension InAppReceiptPayload: ASN1Decodable case InAppReceiptField.originalAppVersion: originalAppVersion = try valueContainer.decode(String.self) case InAppReceiptField.expirationDate: - expirationDate = try valueContainer.decode(String.self, template: .universal(ASN1Identifier.Tag.ia5String)) + let expirationDateString = try valueContainer.decode(String.self, template: .universal(ASN1Identifier.Tag.ia5String)) + expirationDate = expirationDateString.rfc3339date() case InAppReceiptField.receiptCreationDate: - receiptCreationDate = try valueContainer.decode(String.self, template: .universal(ASN1Identifier.Tag.ia5String)) + let receiptCreationDateString = try valueContainer.decode(String.self, template: .universal(ASN1Identifier.Tag.ia5String)) + receiptCreationDate = receiptCreationDateString.rfc3339date() case InAppReceiptField.environment: environment = try valueContainer.decode(String.self) default: @@ -171,10 +173,14 @@ extension InAppPurchase: ASN1Decodable { public init(from decoder: Decoder) throws { - self.init() - var container = try decoder.unkeyedContainer() as! ASN1UnkeyedDecodingContainerProtocol + var originalTransactionIdentifier = "" + var productIdentifier = "" + var transactionIdentifier = "" + var purchaseDate: Date! + var originalPurchaseDate: Date! + while !container.isAtEnd { do @@ -196,17 +202,21 @@ extension InAppPurchase: ASN1Decodable case InAppReceiptField.transactionIdentifier: transactionIdentifier = try valueContainer.decode(String.self) case InAppReceiptField.purchaseDate: - purchaseDateString = try valueContainer.decode(String.self, template: .universal(ASN1Identifier.Tag.ia5String)) + let purchaseDateString = try valueContainer.decode(String.self, template: .universal(ASN1Identifier.Tag.ia5String)) + purchaseDate = purchaseDateString.rfc3339date()! case InAppReceiptField.originalTransactionIdentifier: originalTransactionIdentifier = try valueContainer.decode(String.self) case InAppReceiptField.originalPurchaseDate: - originalPurchaseDateString = try valueContainer.decode(String.self, template: .universal(ASN1Identifier.Tag.ia5String)) + let originalPurchaseDateString = try valueContainer.decode(String.self, template: .universal(ASN1Identifier.Tag.ia5String)) + originalPurchaseDate = originalPurchaseDateString.rfc3339date()! case InAppReceiptField.subscriptionExpirationDate: let str = try valueContainer.decode(String.self, template: .universal(ASN1Identifier.Tag.ia5String)) - subscriptionExpirationDateString = str == "" ? nil : str + let subscriptionExpirationDateString = str == "" ? nil : str + subscriptionExpirationDate = subscriptionExpirationDateString?.rfc3339date() case InAppReceiptField.cancellationDate: let str = try valueContainer.decode(String.self, template: .universal(ASN1Identifier.Tag.ia5String)) - cancellationDateString = str == "" ? nil : str + let cancellationDateString = str == "" ? nil : str + cancellationDate = cancellationDateString?.rfc3339date() case InAppReceiptField.webOrderLineItemID: webOrderLineItemID = try valueContainer.decode(Int.self) case InAppReceiptField.subscriptionTrialPeriod: @@ -220,6 +230,12 @@ extension InAppPurchase: ASN1Decodable } } } + + self.originalTransactionIdentifier = originalTransactionIdentifier + self.productIdentifier = productIdentifier + self.transactionIdentifier = transactionIdentifier + self.purchaseDate = purchaseDate + self.originalPurchaseDate = originalPurchaseDate } public static var template: ASN1Template diff --git a/Sources/InAppReceipt.swift b/Sources/InAppReceipt.swift index 8635051..fd791a4 100644 --- a/Sources/InAppReceipt.swift +++ b/Sources/InAppReceipt.swift @@ -115,7 +115,7 @@ public extension InAppReceipt /// The date that the app receipt expires var expirationDate: Date? { - return payload.expirationDate?.rfc3339date() + return payload.expirationDate } /// Returns `true` if any purchases exist, `false` otherwise @@ -130,10 +130,10 @@ public extension InAppReceipt return activeAutoRenewableSubscriptionPurchases.count > 0 } - /// The date when the app receipt was created. + var creationDate: Date { - return payload.creationDate.rfc3339date()! + return payload.creationDate } /// In App Receipt in base64 diff --git a/Sources/InAppReceiptPayload.swift b/Sources/InAppReceiptPayload.swift index 2be403a..faf6634 100644 --- a/Sources/InAppReceiptPayload.swift +++ b/Sources/InAppReceiptPayload.swift @@ -24,7 +24,7 @@ struct InAppReceiptPayload let originalAppVersion: String /// The date that the app receipt expires - let expirationDate: String? + let expirationDate: Date? /// Used to validate the receipt let bundleIdentifierData: Data @@ -36,7 +36,7 @@ struct InAppReceiptPayload let receiptHash: Data /// The date when the app receipt was created. - let creationDate: String + let creationDate: Date /// Receipt's environment let environment: String @@ -46,7 +46,7 @@ struct InAppReceiptPayload /// Initialize a `InAppReceipt` passing all values /// - init(bundleIdentifier: String, appVersion: String, originalAppVersion: String, purchases: [InAppPurchase], expirationDate: String?, bundleIdentifierData: Data, opaqueValue: Data, receiptHash: Data, creationDate: String, environment: String, rawData: Data) + init(bundleIdentifier: String, appVersion: String, originalAppVersion: String, purchases: [InAppPurchase], expirationDate: Date?, bundleIdentifierData: Data, opaqueValue: Data, receiptHash: Data, creationDate: Date, environment: String, rawData: Data) { self.bundleIdentifier = bundleIdentifier self.appVersion = appVersion diff --git a/Tests/TPInAppReceiptTests/PerformanceTests.swift b/Tests/TPInAppReceiptTests/PerformanceTests.swift index 5519e24..11ecfc1 100644 --- a/Tests/TPInAppReceiptTests/PerformanceTests.swift +++ b/Tests/TPInAppReceiptTests/PerformanceTests.swift @@ -15,14 +15,25 @@ class PerformanceTests: XCTestCase override func setUp() { - receipt = try! InAppReceipt(receiptData: crashReceipt) + receipt = try! InAppReceipt(receiptData: legacyReceipt) } override func tearDown() { // Put teardown code here. This method is called after the invocation of each test method in the class. } - + func testParsingPerformance() { // / 0.004 + // This is an example of a performance test case. + self.measure { + do + { + let receipt = try! InAppReceipt(receiptData: legacyReceipt) + print(123) + }catch{ + XCTFail("Unable to verify: \(error)") + } + } + } func testValidationPerformance() { // / 0.004 // This is an example of a performance test case. diff --git a/Tests/TPInAppReceiptTests/TPInAppReceiptTests.swift b/Tests/TPInAppReceiptTests/TPInAppReceiptTests.swift index d1de8d6..3f0af49 100644 --- a/Tests/TPInAppReceiptTests/TPInAppReceiptTests.swift +++ b/Tests/TPInAppReceiptTests/TPInAppReceiptTests.swift @@ -12,8 +12,8 @@ final class TPInAppReceiptTests: XCTestCase { func testNewReceipt() { self.measure { - let r = try! InAppReceipt(receiptData: watchReceipt) - //XCTAssert(r.appVersion == 1) + let r = try! InAppReceipt(receiptData: newReceipt) + print(r.creationDate) } }