tikhop / TPInAppReceipt

Reading and Validating In App Purchase Receipt Locally.
MIT License
631 stars 93 forks source link

Fatal Crash: Unexpectedly found nil while implicitly unwrapping an Optional value #83

Closed Jerland2 closed 3 years ago

Jerland2 commented 3 years ago

Version: TPInAppReceipt 3.1.0 using SPM Setup: Testing in sandbox env using IAP configuration file. Crash: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: file TPInAppReceipt/InAppReceipt+ASN1Decodable.swift, line 242

        while !container.isAtEnd
        {
            do
            {
                var attributeContainer = try container.nestedUnkeyedContainer(for: ReceiptAttribute.template) as! ASN1UnkeyedDecodingContainerProtocol
                let type: Int32 = try attributeContainer.decode(Int32.self)
                let _ = try attributeContainer.skip(template: .universal(ASN1Identifier.Tag.integer)) // Consume
                var valueContainer = try attributeContainer.nestedUnkeyedContainer(for: .universal(ASN1Identifier.Tag.octetString)) as! ASN1UnkeyedDecodingContainerProtocol
                //let attribute = try container.decode(ReceiptAttribute.self)

                switch type
                {
                case InAppReceiptField.quantity:
                    quantity = try valueContainer.decode(Int.self)
                case InAppReceiptField.productIdentifier:
                    productIdentifier = try valueContainer.decode(String.self)
                case InAppReceiptField.productType:
                    productType = Type(rawValue: try valueContainer.decode(Int32.self)) ?? .unknown
                case InAppReceiptField.transactionIdentifier:
                    transactionIdentifier = try valueContainer.decode(String.self)
                case InAppReceiptField.purchaseDate:
                    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:
                    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))
                    let subscriptionExpirationDateString = str == "" ? nil : str
                    subscriptionExpirationDate = subscriptionExpirationDateString?.rfc3339date()
                case InAppReceiptField.cancellationDate:
                    let str = try valueContainer.decode(String.self, template: .universal(ASN1Identifier.Tag.ia5String))
                    let cancellationDateString = str == "" ? nil : str
                    cancellationDate = cancellationDateString?.rfc3339date()
                case InAppReceiptField.webOrderLineItemID:
                    webOrderLineItemID = try valueContainer.decode(Int.self)
                case InAppReceiptField.subscriptionTrialPeriod:
                    subscriptionTrialPeriod = (try valueContainer.decode(Int32.self)) != 0
                case InAppReceiptField.subscriptionIntroductoryPricePeriod:
                    subscriptionIntroductoryPricePeriod = (try valueContainer.decode(Int32.self)) != 0
                case InAppReceiptField.promotionalOfferIdentifier:
                    promotionalOfferIdentifier = try valueContainer.decode(String.self)
                default:
                    break
                }
            }
        }

        self.originalTransactionIdentifier = originalTransactionIdentifier
        self.productIdentifier = productIdentifier
        self.transactionIdentifier = transactionIdentifier
        self.purchaseDate = purchaseDate
        self.originalPurchaseDate = originalPurchaseDate // FATAL ERROR OCCURS HERE
    }

This causes application to crash on all subsequent runs after purchasing the first IAP. Fatal error commented with "// FATAL ERROR OCCURS HERE" in the above snippet.

Will be rolling back to 3.0.2 until resolved. 3.0.2 does not exhibit this behavior.

tikhop commented 3 years ago

Hi @Jerland2,

Thanks for the report, I'm looking into it.

tikhop commented 3 years ago

@Jerland2 Confirmed. I will push a fix in a few. Thanks again.

tikhop commented 3 years ago

@Jerland2 Just updated cocoapods. Thanks again for the report.