Skip to content

Commit

Permalink
Check Apple's LatestReceiptInfo for non-subscription purchases
Browse files Browse the repository at this point in the history
Closes #971
  • Loading branch information
hhhapz committed Feb 20, 2024
1 parent fe4676d commit 13561e2
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 3 deletions.
2 changes: 1 addition & 1 deletion iap/iap.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ type ValidateReceiptAppleResponse struct {
Environment string `json:"environment"` // possible values: 'Sandbox', 'Production'.
IsRetryable bool `json:"is-retryable"` // If true, request must be retried later.
LatestReceipt string `json:"latest_receipt"`
LatestReceiptInfo []ValidateReceiptAppleResponseLatestReceiptInfo `json:"latest_receipt_info"` // Only returned for auto-renewable subscriptions.
LatestReceiptInfo []ValidateReceiptAppleResponseLatestReceiptInfo `json:"latest_receipt_info"`
PendingRenewalInfo []ValidateReceiptAppleResponsePendingRenewalInfo `json:"pending_renewal_info"` // Only returned for auto-renewable subscriptions.
Receipt *ValidateReceiptAppleResponseReceipt `json:"receipt"`
Status int `json:"status"`
Expand Down
26 changes: 24 additions & 2 deletions server/core_purchase.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func ValidatePurchasesApple(ctx context.Context, logger *zap.Logger, db *sql.DB,
env = api.StoreEnvironment_SANDBOX
}

storagePurchases := make([]*storagePurchase, 0, len(validation.Receipt.InApp))
storagePurchases := make([]*storagePurchase, 0, len(validation.Receipt.InApp)+len(validation.LatestReceiptInfo))
for _, purchase := range validation.Receipt.InApp {
if purchase.ExpiresDateMs != "" {
continue
Expand All @@ -88,8 +88,30 @@ func ValidatePurchasesApple(ctx context.Context, logger *zap.Logger, db *sql.DB,
environment: env,
})
}
// latest_receipt_info can also contaion purchases.
// https://developer.apple.com/forums/thread/63092
for _, purchase := range validation.LatestReceiptInfo {
if purchase.ExpiresDateMs != "" {
continue
}

purchaseTime, err := strconv.ParseInt(purchase.PurchaseDateMs, 10, 64)
if err != nil {
return nil, err
}

storagePurchases = append(storagePurchases, &storagePurchase{
userID: userID,
store: api.StoreProvider_APPLE_APP_STORE,
productId: purchase.ProductId,
transactionId: purchase.TransactionId,
rawResponse: string(raw),
purchaseTime: parseMillisecondUnixTimestamp(purchaseTime),
environment: env,
})
}

if len(storagePurchases) == 0 && len(validation.Receipt.InApp) > 0 {
if len(storagePurchases) == 0 && len(validation.Receipt.InApp)+len(validation.LatestReceiptInfo) > 0 {
// All purchases in this receipt are subscriptions.
return nil, status.Error(codes.FailedPrecondition, "Subscription Receipt. Use the appropriate function instead.")
}
Expand Down

0 comments on commit 13561e2

Please sign in to comment.