From a47d4cb5a7e004f5dca4e2eb26167406b4eac16b Mon Sep 17 00:00:00 2001 From: Hannes Oud Date: Fri, 6 Nov 2020 13:02:09 +0100 Subject: [PATCH] Restore UnofficialReceipt parsing after transitioning to ASN1Decoder --- .../AppReceiptValidator.swift | 36 +++++++++++++++++-- .../UnofficialReceipt.swift | 9 ++--- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/AppReceiptValidator/AppReceiptValidator/AppReceiptValidator.swift b/AppReceiptValidator/AppReceiptValidator/AppReceiptValidator.swift index c9982f4..009fa75 100644 --- a/AppReceiptValidator/AppReceiptValidator/AppReceiptValidator.swift +++ b/AppReceiptValidator/AppReceiptValidator/AppReceiptValidator.swift @@ -201,7 +201,37 @@ private extension AppReceiptValidator { receipt.originalAppVersion = contents.originalApplicationVersion receipt.expirationDate = contents.receiptExpirationDate - return (receipt: receipt, unofficialReceipt: .init(entries: [])) + return (receipt: receipt, unofficialReceipt: (parseUnofficialParts ? self.parseUnofficialReceipt(pkcs7: pkcs7) : .init(entries: []))) + } + + func parseUnofficialReceipt(pkcs7: ASN1Decoder.PKCS7) -> UnofficialReceipt { + guard let receiptBlock = pkcs7.mainBlock.findOid(.pkcs7data)?.parent?.sub?.last?.sub(0)?.sub(0), + let items = receiptBlock.sub else { return .init(entries: []) } + + let entries: [UnofficialReceipt.Entry] = items.compactMap { item in + guard let fieldType = (item.sub(0)?.value as? Data)?.toIntValue(), + KnownReceiptAttribute(rawValue: fieldType) == nil else { return nil } + + let fieldValueString = item.sub(2)?.asString + if let meaning = KnownUnofficialReceiptAttribute(rawValue: fieldType) { + switch meaning.parsingType { + case .string: + if let string = fieldValueString { + return UnofficialReceipt.Entry(attributeNumber: fieldType, meaning: meaning, value: .string(string)) + } + case .data: + if let data = item.sub(2)?.rawValue { + return UnofficialReceipt.Entry(attributeNumber: fieldType, meaning: meaning, value: .bytes(data)) + } + } + } + + if let string = fieldValueString { + return UnofficialReceipt.Entry(attributeNumber: fieldType, meaning: nil, value: .string(string)) + } + return UnofficialReceipt.Entry(attributeNumber: fieldType, meaning: nil, value: item.sub(2)?.rawValue.map { .bytes($0) }) + } + return UnofficialReceipt(entries: entries) } } @@ -210,7 +240,7 @@ private extension AppReceiptValidator { private extension AppReceiptValidator { /// See Receipt.swift for details and a link to Apple reference - enum KnownReceiptAttribute: Int32 { + enum KnownReceiptAttribute: UInt64 { case bundleIdentifier = 2 case appVersion = 3 case opaqueValue = 4 @@ -222,7 +252,7 @@ private extension AppReceiptValidator { } /// See Receipt.swift for details and a link to Apple reference - enum KnownInAppPurchaseAttribute: Int32 { + enum KnownInAppPurchaseAttribute: UInt64 { case quantity = 1701 case productIdentifier = 1702 case transactionIdentifier = 1703 diff --git a/AppReceiptValidator/AppReceiptValidator/UnofficialReceipt.swift b/AppReceiptValidator/AppReceiptValidator/UnofficialReceipt.swift index e30f10b..f5e5f87 100644 --- a/AppReceiptValidator/AppReceiptValidator/UnofficialReceipt.swift +++ b/AppReceiptValidator/AppReceiptValidator/UnofficialReceipt.swift @@ -22,7 +22,7 @@ public struct UnofficialReceipt { case bytes(Data) } - public internal(set) var attributeNumber: Int32 + public internal(set) var attributeNumber: UInt64 public internal(set) var meaning: KnownUnofficialReceiptAttribute? public internal(set) var value: Value? } @@ -42,7 +42,7 @@ public struct UnofficialReceipt { } } -public enum KnownUnofficialReceiptAttribute: Int32 { +public enum KnownUnofficialReceiptAttribute: UInt64 { case provisioningType = 0 // String, probably Provisioning-Type, Encountered Values: "Production", "ProductionSandbox", "ProductionVPP" case date1 = 8 // some date, same as receiptCreationDate possibly @@ -54,15 +54,12 @@ public enum KnownUnofficialReceiptAttribute: Int32 { enum ParsingType { case string - case date case data } var parsingType: ParsingType { switch self { - case .date1, .date2, .date3: - return .date - case .provisioningType, .ageRating, .clientName: + case .provisioningType, .ageRating, .clientName, .date1, .date2, .date3: return .string } }