Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
32 changes: 20 additions & 12 deletions Sources/AppStoreServerLibrary/Models/AppTransaction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import Foundation
///[AppTransaction](https://developer.apple.com/documentation/storekit/apptransaction)
public struct AppTransaction: DecodedSignedData, Decodable, Encodable, Hashable, Sendable {

public init(receiptType: AppStoreEnvironment? = nil, appAppleId: Int64? = nil, bundleId: String? = nil, applicationVersion: String? = nil, versionExternalIdentifier: Int64? = nil, receiptCreationDate: Date? = nil, originalPurchaseDate: Date? = nil, originalApplicationVersion: String? = nil, deviceVerification: String? = nil, deviceVerificationNonce: UUID? = nil, preorderDate: Date? = nil, appTransactionId: String? = nil, originalPlatform: PurchasePlatform? = nil) {
self.receiptType = receiptType
public init(environment: AppStoreEnvironment? = nil, appAppleId: Int64? = nil, bundleId: String? = nil, applicationVersion: String? = nil, versionExternalIdentifier: Int64? = nil, receiptCreationDate: Date? = nil, originalPurchaseDate: Date? = nil, originalApplicationVersion: String? = nil, deviceVerification: String? = nil, deviceVerificationNonce: UUID? = nil, preorderDate: Date? = nil, appTransactionId: String? = nil, originalPlatform: PurchasePlatform? = nil) {
self.environment = environment
self.appAppleId = appAppleId
self.bundleId = bundleId
self.applicationVersion = applicationVersion
Expand All @@ -24,8 +24,8 @@ public struct AppTransaction: DecodedSignedData, Decodable, Encodable, Hashable,
self.originalPlatform = originalPlatform
}

public init(rawReceiptType: String? = nil, appAppleId: Int64? = nil, bundleId: String? = nil, applicationVersion: String? = nil, versionExternalIdentifier: Int64? = nil, receiptCreationDate: Date? = nil, originalPurchaseDate: Date? = nil, originalApplicationVersion: String? = nil, deviceVerification: String? = nil, deviceVerificationNonce: UUID? = nil, preorderDate: Date? = nil, appTransactionId: String? = nil, rawOriginalPlatform: String? = nil) {
self.rawReceiptType = rawReceiptType
public init(rawEnvironment: String? = nil, appAppleId: Int64? = nil, bundleId: String? = nil, applicationVersion: String? = nil, versionExternalIdentifier: Int64? = nil, receiptCreationDate: Date? = nil, originalPurchaseDate: Date? = nil, originalApplicationVersion: String? = nil, deviceVerification: String? = nil, deviceVerificationNonce: UUID? = nil, preorderDate: Date? = nil, appTransactionId: String? = nil, rawOriginalPlatform: String? = nil) {
self.rawEnvironment = rawEnvironment
self.appAppleId = appAppleId
self.bundleId = bundleId
self.applicationVersion = applicationVersion
Expand All @@ -43,17 +43,17 @@ public struct AppTransaction: DecodedSignedData, Decodable, Encodable, Hashable,
///The server environment that signs the app transaction.
///
///[environment](https://developer.apple.com/documentation/storekit/apptransaction/3963901-environment)
public var receiptType: AppStoreEnvironment? {
public var environment: AppStoreEnvironment? {
get {
return rawReceiptType.flatMap { AppStoreEnvironment(rawValue: $0) }
return rawEnvironment.flatMap { AppStoreEnvironment(rawValue: $0) }
}
set {
self.rawReceiptType = newValue.map { $0.rawValue }
self.rawEnvironment = newValue.map { $0.rawValue }
}
}

///See ``receiptType``
public var rawReceiptType: String?
///See ``environment``
public var rawEnvironment: String?

///The unique identifier the App Store uses to identify the app.
///
Expand Down Expand Up @@ -135,7 +135,8 @@ public struct AppTransaction: DecodedSignedData, Decodable, Encodable, Hashable,


public enum CodingKeys: CodingKey {
case receiptType
case environment
case receiptType // For backward compatibility
case appAppleId
case bundleId
case applicationVersion
Expand All @@ -152,7 +153,14 @@ public struct AppTransaction: DecodedSignedData, Decodable, Encodable, Hashable,

public init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.rawReceiptType = try container.decodeIfPresent(String.self, forKey: .receiptType)
// Try environment first, then fall back to receiptType for backward compatibility
if let environmentValue = try container.decodeIfPresent(String.self, forKey: .environment) {
self.rawEnvironment = environmentValue
} else if let receiptTypeValue = try container.decodeIfPresent(String.self, forKey: .receiptType) {
self.rawEnvironment = receiptTypeValue
} else {
self.rawEnvironment = nil
}
self.appAppleId = try container.decodeIfPresent(Int64.self, forKey: .appAppleId)
self.bundleId = try container.decodeIfPresent(String.self, forKey: .bundleId)
self.applicationVersion = try container.decodeIfPresent(String.self, forKey: .applicationVersion)
Expand All @@ -169,7 +177,7 @@ public struct AppTransaction: DecodedSignedData, Decodable, Encodable, Hashable,

public func encode(to encoder: any Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeIfPresent(self.rawReceiptType, forKey: .receiptType)
try container.encodeIfPresent(self.rawEnvironment, forKey: .environment)
try container.encodeIfPresent(self.appAppleId, forKey: .appAppleId)
try container.encodeIfPresent(self.bundleId, forKey: .bundleId)
try container.encodeIfPresent(self.applicationVersion, forKey: .applicationVersion)
Expand Down
2 changes: 1 addition & 1 deletion Sources/AppStoreServerLibrary/SignedDataVerifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ public struct SignedDataVerifier {
let appTransactionResult = await decodeSignedData(signedData: signedAppTransaction, type: AppTransaction.self)
switch appTransactionResult {
case .valid(let appTransaction):
let environment = appTransaction.receiptType
let environment = appTransaction.environment
if self.bundleId != appTransaction.bundleId || (self.environment == .production && self.appAppleId != appTransaction.appAppleId) {
return VerificationResult.invalid(VerificationError.INVALID_APP_IDENTIFIER)
}
Expand Down
4 changes: 2 additions & 2 deletions Tests/AppStoreServerLibraryTests/SignedModelTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,8 @@ final class SignedModelTests: XCTestCase {
return
}

XCTAssertEqual(AppStoreEnvironment.localTesting, appTransaction.receiptType)
XCTAssertEqual("LocalTesting", appTransaction.rawReceiptType)
XCTAssertEqual(AppStoreEnvironment.localTesting, appTransaction.environment)
XCTAssertEqual("LocalTesting", appTransaction.rawEnvironment)
XCTAssertEqual(531412, appTransaction.appAppleId)
XCTAssertEqual("com.example", appTransaction.bundleId)
XCTAssertEqual("1.2.3", appTransaction.applicationVersion)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ final class XcodeSignedDataVerifierTests: XCTestCase {
XCTAssertEqual("cYUsXc53EbYc0pOeXG5d6/31LGHeVGf84sqSN0OrJi5u/j2H89WWKgS8N0hMsMlf", appTransaction.deviceVerification)
XCTAssertEqual(UUID(uuidString: "48c8b92d-ce0d-4229-bedf-e61b4f9cfc92"), appTransaction.deviceVerificationNonce)
XCTAssertNil(appTransaction.preorderDate)
XCTAssertEqual(.xcode, appTransaction.receiptType)
XCTAssertEqual("Xcode", appTransaction.rawReceiptType)
XCTAssertEqual(.xcode, appTransaction.environment)
XCTAssertEqual("Xcode", appTransaction.rawEnvironment)
confirmCodableInternallyConsistentForXcode(appTransaction)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"receiptType": "LocalTesting",
"environment": "LocalTesting",
"appAppleId": 531412,
"bundleId": "com.example",
"applicationVersion": "1.2.3",
Expand Down