Accept bounded StoreKit signing clock skew
Allow legitimate App Store transaction timestamps to differ within the existing verification tolerance while preserving rejection beyond that boundary.
This commit is contained in:
@@ -123,7 +123,7 @@ class StoreKitService(
|
||||
}
|
||||
val now = clock.instant()
|
||||
if (
|
||||
transaction.purchasedAt > transaction.signedAt ||
|
||||
transaction.purchasedAt > transaction.signedAt.plus(MAX_CLOCK_SKEW) ||
|
||||
transaction.signedAt > now.plus(MAX_CLOCK_SKEW)
|
||||
) {
|
||||
throw StoreKitPurchaseConflict()
|
||||
|
||||
@@ -33,14 +33,16 @@ class StoreKitServiceTest : FunSpec({
|
||||
accountToken: UUID = userId,
|
||||
productId: String = product.productId,
|
||||
revokedAt: Instant? = null,
|
||||
purchasedAt: Instant = now.minusSeconds(10),
|
||||
signedAt: Instant = now.minusSeconds(5),
|
||||
) = VerifiedStoreKitTransaction(
|
||||
transactionId = transactionId,
|
||||
originalTransactionId = transactionId,
|
||||
appAccountToken = accountToken,
|
||||
productId = productId,
|
||||
environment = StoreKitEnvironment.SANDBOX,
|
||||
purchasedAt = now.minusSeconds(10),
|
||||
signedAt = now.minusSeconds(5),
|
||||
purchasedAt = purchasedAt,
|
||||
signedAt = signedAt,
|
||||
revokedAt = revokedAt,
|
||||
)
|
||||
|
||||
@@ -115,6 +117,33 @@ class StoreKitServiceTest : FunSpec({
|
||||
store.ledger shouldHaveSize 0
|
||||
}
|
||||
|
||||
test("small App Store signing clock skew is accepted") {
|
||||
val store = TestBillingStore()
|
||||
val verified = transaction(
|
||||
purchasedAt = now.minusSeconds(10),
|
||||
signedAt = now.minusSeconds(70),
|
||||
)
|
||||
|
||||
val result = service(store, verified).submit(userId, signedTransaction)
|
||||
|
||||
result.balanceAfter shouldBeExactly 3_000
|
||||
store.ledger shouldHaveSize 1
|
||||
}
|
||||
|
||||
test("App Store signing clock skew beyond the tolerance is rejected") {
|
||||
val store = TestBillingStore()
|
||||
val verified = transaction(
|
||||
purchasedAt = now.minusSeconds(10),
|
||||
signedAt = now.minusSeconds(311),
|
||||
)
|
||||
|
||||
shouldThrow<StoreKitPurchaseConflict> {
|
||||
service(store, verified).submit(userId, signedTransaction)
|
||||
}
|
||||
|
||||
store.ledger shouldHaveSize 0
|
||||
}
|
||||
|
||||
test("unknown or revoked products never grant credits") {
|
||||
val unknownStore = TestBillingStore()
|
||||
shouldThrow<StoreKitPurchaseConflict> {
|
||||
|
||||
Reference in New Issue
Block a user