Mark Villacampa and NachoSoto
84806ad86e
Improve sandbox detector for macOS apps ( #3549 )
...
Checking for the presence of `Xcode/DerivedData` in the receipt path was
failing for TestFlight builds or if the .app bundle generated by Xcode
was moved from the folder.
Additionally, checking for `MASReceipt/receipt` seems less robust than
simply using compiler directives.
Instead, for macOS apps, we check the environment embedded in the receipt and alternatively check the signature of the app bundle.
---------
Co-authored-by: NachoSoto <NachoSoto@users.noreply.github.com >
2024-01-09 19:12:47 +01:00
NachoSoto
82435936d9
Xcode 13: remove conditional code (#3147 )
...
Clean up thanks to #2421
2023-09-06 10:59:22 -07:00
NachoSoto
2276d5c2ce
AppleReceipt.debugDescription: don't pretty-print JSON (#2564 )
2023-05-31 07:11:23 -07:00
NachoSoto
e6e79c95a7
AppleReceipt.mostRecentActiveSubscription: performance optimization (#2332 )
...
No need to sort the entire list of subscriptions
2023-03-13 14:19:19 -07:00
NachoSoto
fdd7874deb
IntroEligibilityCalculator: fixed logic for subscriptions in same group (#2174 )
...
- Fixes [TRIAGE-221] for `SK1`.
- Filed `FB11889732` for `SK2`.
### Changes:
- Added 2 `IntroEligibilityCalculatorTests` unit tests to cover this
scenario
- Added 1 `IntroEligibilityCalculatorTests` unit tests to cover the
equivalent of the `testIneligibleForIntroAfterPurchaseExpires`
integration test
- Added 2 `StoreKitIntegrationTests` to cover this scenario (one of them
disabled in SK2)
- Updated `IntroEligibilityCalculator` logic to fix the new tests.
- Refactored `IntroEligibilityCalculatorTests` to avoid duplication and
allow adding new cases more easily.
- Added a few more tests to ensure other cases are correct.
[TRIAGE-221]:
https://revenuecats.atlassian.net/browse/TRIAGE-221?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
2023-01-25 08:40:35 -08:00
NachoSoto
0819eca3e8
Restore purchases: post product data when posting receipts (#2178 )
...
Fixes [CSDK-604].
When restore receipts, we don't post any price for products because we
don't know what the user bought.
As a best-effort approach, this parses the `AppleReceipt` and looks for
products that were purchased.
[CSDK-604]:
https://revenuecats.atlassian.net/browse/CSDK-604?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
2022-12-27 10:13:07 -08:00
NachoSoto
3b7c93c2b7
ReceiptParser: a few documentation improvements (#2189 )
2022-12-22 11:24:27 -08:00
NachoSoto
b3875a9380
Exposed PurchasesReceiptParser and AppleReceipt ( #2153 )
...
Initial step for [CSDK-17]. Fixes [CSDK-523].
### Changes:
- Renamed `ReceiptParser` to `PurchasesReceiptParser` to avoid name
collision with future SPM `ReceiptParser`
- Exposed `ReceiptParser`, `AppleReceipt`,
`PurchasesReceiptParser.Error`
- Added new types to `SwiftAPITester`
- Added docs to these types
- Moved `LoggerType` to be available to `ReceiptParser`
- Moved `DateFormatter+Extensions` to be available to `ReceiptParser`
- Moved `Codable+Extensions` to be available to `ReceiptParser`
- Created `ReceiptParserLogger` for `ReceiptParser`
[CSDK-17]:
https://revenuecats.atlassian.net/browse/CSDK-17?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
[CSDK-523]:
https://revenuecats.atlassian.net/browse/CSDK-523?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
2022-12-22 10:09:12 -08:00
NachoSoto
8b4a9ecbca
PostReceiptDataOperation: log Apple error when purchase equals expiration date (#2038 )
...
A large amount of flaky integration tests are due to this bug, so
detecting it early in the logs will help debug this.
Radar: `FB11767559`.
`productType` is missing in `StoreKitTest` purchases, so I changed
`isSubscription` to default to checking if there is an expiration when
the type is `.unknown`.
To simplify the code, I changed `ProductType?` to be non-optional, since
we already have `.unknown` as a case.
### Example:
```
[00:27:56]: ▸ 2022-11-09 00:27:56.000533+0000 BackendIntegrationTestsHostApp[3942:17000] [Purchases] - DEBUG: ℹ️ PostReceiptDataOperation: Posting receipt: {
[00:27:56]: ▸ "opaque_value" : "1n+XXw8AAAA=",
[00:27:56]: ▸ "sha1_hash" : "unR7vAzPaUlB0TtZ09z5jMyqqAs=",
[00:27:56]: ▸ "bundle_id" : "com.revenuecat.StoreKitTestApp",
[00:27:56]: ▸ "in_app_purchases" : [
[00:27:56]: ▸ {
[00:27:56]: ▸ "quantity" : 1,
[00:27:56]: ▸ "product_id" : "com.revenuecat.weekly_1.99.3_day_intro",
[00:27:56]: ▸ "purchase_date" : "2022-11-09T00:27:50Z",
[00:27:56]: ▸ "transaction_id" : "0",
[00:27:56]: ▸ "is_in_intro_offer_period" : true,
[00:27:56]: ▸ "expires_date" : "2022-11-09T00:27:50Z"
[00:27:56]: ▸ },
[00:27:56]: ▸ {
[00:27:56]: ▸ "product_id" : "com.revenuecat.weekly_1.99.3_day_intro",
[00:27:56]: ▸ "quantity" : 1,
[00:27:56]: ▸ "transaction_id" : "1",
[00:27:56]: ▸ "is_in_intro_offer_period" : false,
[00:27:56]: ▸ "expires_date" : "2022-11-09T00:28:00Z",
[00:27:56]: ▸ "original_purchase_date" : "2022-11-09T00:27:50Z",
[00:27:56]: ▸ "original_transaction_id" : "0",
[00:27:56]: ▸ "purchase_date" : "2022-11-09T00:27:50Z"
[00:27:56]: ▸ }
[00:27:56]: ▸ ],
[00:27:56]: ▸ "application_version" : "1",
[00:27:56]: ▸ "creation_date" : "2022-11-09T00:27:55Z",
[00:27:56]: ▸ "expiration_date" : "4001-01-01T00:00:00Z"
[00:27:56]: ▸ }
[00:27:56]: ▸ 2022-11-09 00:27:56.000710+0000 BackendIntegrationTestsHostApp[3942:17000] [Purchases] - ERROR: 🍎 ‼️ Receipt for product 'com.revenuecat.weekly_1.99.3_day_intro' has the same purchase (2022-11-09 00:27:50 +0000) and expiration (2022-11-09 00:27:50 +0000) dates. This is likely a StoreKit bug.
```
2022-11-09 11:18:52 -08:00
NachoSoto and Cesar de la Vega
c00be57a13
ReceiptFetcher: added retry mechanism (#1945 )
...
Fixes [CSDK-478]
~~Depends on #1941 , #1942 , and #1943.~~
### Example:
Log of a successful purchase after retrying 🎉
> INFO: 💰 Purchasing Product 'com.revenuecat.monthly_4.99.1_week_intro'
DEBUG: ℹ️ Loaded receipt from url
file:///Users/nachosoto/Library/Developer/CoreSimulator/Devices/A3576DC2-355E-45BA-B32C-D2C0A3811BB4/data/Containers/Data/Application/7ACD12DA-2A12-4CF1-8A76-8295E40B64EF/StoreKit/receipt
INFO: ℹ️ Receipt parsed successfully
WARN: 🍎 ‼️ Local receipt is still missing purchase for
'com.revenuecat.monthly_4.99.1_week_intro':
{
"opaque_value" : "79v2XwwAAAA=",
"sha1_hash" : "GhOmfuioo2Z4R3zX8K60l4b0qgs=",
"bundle_id" : "com.revenuecat.StoreKitTestApp",
"in_app_purchases" : [
{
"quantity" : 1,
"product_id" : "com.revenuecat.monthly_4.99.1_week_intro",
"purchase_date" : "2022-09-28T01:14:24Z",
"transaction_id" : "0",
"is_in_intro_offer_period" : true,
"expires_date" : "2022-09-28T01:14:34Z"
}
],
"application_version" : "1",
"creation_date" : "2022-09-28T01:14:24Z",
"expiration_date" : "4001-01-01T00:00:00Z"
}
DEBUG: ℹ️ Retrying Receipt fetch after 5 seconds
DEBUG: ℹ️ API request completed: POST /v1/receipts 200
DEBUG: ℹ️ PostReceiptDataOperation: Finished
DEBUG: ℹ️ Serial request done: POST receipts, 0 requests left in the
queue
DEBUG: ℹ️ Sending updated CustomerInfo to delegate.
DEBUG: ℹ️ Found 0 unsynced attributes for App User ID:
$RCAnonymousID:ec326c1613c14b489980eace90dceabb
DEBUG: ℹ️ Force refreshing the receipt to get latest transactions from
Apple.
DEBUG: ℹ️ Loaded receipt from url
file:///Users/nachosoto/Library/Developer/CoreSimulator/Devices/A3576DC2-355E-45BA-B32C-D2C0A3811BB4/data/Containers/Data/Application/7ACD12DA-2A12-4CF1-8A76-8295E40B64EF/StoreKit/receipt
DEBUG: ℹ️ PostReceiptDataOperation: Started
INFO: ℹ️ Receipt parsed successfully
DEBUG: ℹ️ PostReceiptDataOperation: Posting receipt: {
"opaque_value" : "0nf1uwEAAAA=",
"sha1_hash" : "lfxVVsBuSkQLtrGJseZ8zlpXc5A=",
"bundle_id" : "com.revenuecat.StoreKitTestApp",
"in_app_purchases" : [
{
"quantity" : 1,
"product_id" : "com.revenuecat.monthly_4.99.1_week_intro",
"purchase_date" : "2022-09-28T01:14:24Z",
"transaction_id" : "0",
"is_in_intro_offer_period" : true,
"expires_date" : "2022-09-28T01:14:34Z"
},
{
"product_id" : "com.revenuecat.monthly_4.99.1_week_intro",
"quantity" : 1,
"transaction_id" : "1",
"is_in_intro_offer_period" : false,
"expires_date" : "2022-09-28T01:15:04Z",
"original_purchase_date" : "2022-09-28T01:14:24Z",
"original_transaction_id" : "0",
"purchase_date" : "2022-09-28T01:14:34Z"
}
],
"application_version" : "1",
"creation_date" : "2022-09-28T01:14:35Z",
"expiration_date" : "4001-01-01T00:00:00Z"
}
DEBUG: ℹ️ There are no requests currently running, starting request POST
receipts
DEBUG: ℹ️ API request started: POST /v1/receipts
DEBUG: ℹ️ API request completed: POST /v1/receipts 200
DEBUG: ℹ️ PostReceiptDataOperation: Finished
DEBUG: ℹ️ Serial request done: POST receipts, 0 requests left in the
queue
DEBUG: ℹ️ Sending updated CustomerInfo to delegate.
DEBUG: ℹ️ Loaded receipt from url
file:///Users/nachosoto/Library/Developer/CoreSimulator/Devices/A3576DC2-355E-45BA-B32C-D2C0A3811BB4/data/Containers/Data/Application/7ACD12DA-2A12-4CF1-8A76-8295E40B64EF/StoreKit/receipt
INFO: ℹ️ Receipt parsed successfully
DEBUG: ℹ️ Skipping products request because products were already
cached. products: ["com.revenuecat.monthly_4.99.1_week_intro"]
DEBUG: ℹ️ Skipping products request because products were already
cached. products: ["com.revenuecat.monthly_4.99.1_week_intro"]
DEBUG: ℹ️ Store products request finished
DEBUG: ℹ️ Found 0 unsynced attributes for App User ID:
$RCAnonymousID:ec326c1613c14b489980eace90dceabb
DEBUG: ℹ️ PostReceiptDataOperation: Started
INFO: ℹ️ Receipt parsed successfully
DEBUG: ℹ️ PostReceiptDataOperation: Posting receipt: {
"opaque_value" : "tv4\/2gcAAAA=",
"sha1_hash" : "0rh1naTc3JyfM16M\/1f6fw4ezAY=",
"bundle_id" : "com.revenuecat.StoreKitTestApp",
"in_app_purchases" : [
{
"quantity" : 1,
"product_id" : "com.revenuecat.monthly_4.99.1_week_intro",
"purchase_date" : "2022-09-28T01:14:24Z",
"transaction_id" : "0",
"is_in_intro_offer_period" : true,
"expires_date" : "2022-09-28T01:14:34Z"
},
{
"product_id" : "com.revenuecat.monthly_4.99.1_week_intro",
"quantity" : 1,
"transaction_id" : "1",
"is_in_intro_offer_period" : false,
"expires_date" : "2022-09-28T01:15:04Z",
"original_purchase_date" : "2022-09-28T01:14:24Z",
"original_transaction_id" : "0",
"purchase_date" : "2022-09-28T01:14:34Z"
}
],
"application_version" : "1",
"creation_date" : "2022-09-28T01:14:40Z",
"expiration_date" : "4001-01-01T00:00:00Z"
}
DEBUG: ℹ️ There are no requests currently running, starting request POST
receipts
DEBUG: ℹ️ API request started: POST /v1/receipts
DEBUG: ℹ️ API request completed: POST /v1/receipts 200
DEBUG: ℹ️ PostReceiptDataOperation: Finished
DEBUG: ℹ️ Serial request done: POST receipts, 0 requests left in the
queue
INFO: 😻 💰 Purchased product - 'com.revenuecat.monthly_4.99.1_week_intro'
[CSDK-478]:
https://revenuecats.atlassian.net/browse/CSDK-478?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
Co-authored-by: Cesar de la Vega <cesarvegaro@gmail.com >
2022-10-07 07:55:53 -07:00
NachoSoto
9ad9e9b108
Moved InAppPurchase into AppleReceipt ( #1942 )
...
The name `InAppPurchase` is too general. This type in particular is
specific to the content of `AppleReceipt`, so nesting it makes that
clear.
Follow up to #1933 .
2022-09-28 08:40:17 -07:00
NachoSoto
b32859d0c8
PostReceiptDataOperation: print receipt data if debug logs are enabled (#1940 )
...
For [CSDK-478].
Follow up to #1929 .
### Example:
> DEBUG: ℹ️ PostReceiptDataOperation: Started
INFO: ℹ️ Receipt parsed successfully
DEBUG: ℹ️ PostReceiptDataOperation: Posting receipt: {
"opaque_value" : "Rn\/39QYAAAA=",
"sha1_hash" : "Ii8Z7ocZm524eJcWFOvVauNrNHs=",
"bundle_id" : "com.revenuecat.StoreKitTestApp",
"in_app_purchases" : [
{
"quantity" : 1,
"product_id" : "com.revenuecat.monthly_4.99.1_week_intro",
"purchase_date" : "2022-09-27T19:09:47Z",
"transaction_id" : "0",
"is_in_intro_offer_period" : true,
"expires_date" : "2022-09-27T19:09:57Z"
}
],
"application_version" : "1",
"creation_date" : "2022-09-27T19:09:47Z",
"expiration_date" : "4001-01-01T00:00:00Z"
}
DEBUG: ℹ️ There are no requests currently running, starting request POST
receipts
DEBUG: ℹ️ API request started: POST /v1/receipts
DEBUG: ℹ️ API request completed: POST /v1/receipts 200
DEBUG: ℹ️ PostReceiptDataOperation: Finished
DEBUG: ℹ️ Serial request done: POST receipts, 0 requests left in the
queue
DEBUG: ℹ️ Sending updated CustomerInfo to delegate.
INFO: 😻 💰 Purchased product - 'com.revenuecat.monthly_4.99.1_week_intro'
INFO: 💰 Finishing transaction com.revenuecat.monthly_4.99.1_week_intro 0
()
[CSDK-478]:
https://revenuecats.atlassian.net/browse/CSDK-478?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
2022-09-27 12:50:34 -07:00
NachoSoto
adf6353c83
AppleReceipt: refactored declarations into nested types (#1933 )
...
Before this change we had a lot of global types. Now they're all nested
inside of `AppleReceipt`, `InAppPurchase`, and `InAppPurchaseBuilder`.
2022-09-23 10:38:14 -07:00
NachoSoto
c4cfdb19e2
StoreKitIntegrationTests: print AppleReceipt data whenever verifyEntitlementWentThrough fails (#1929 )
...
This will help us debug flaky tests.
Example:
> INFO: 😻 💰 Purchased product -
'com.revenuecat.monthly_4.99.1_week_intro'
DEBUG: ℹ️ Force refreshing the receipt to get latest transactions from
Apple.
DEBUG: ℹ️ Loaded receipt from url
file:///Users/nachosoto/Library/Developer/CoreSimulator/Devices/A3576DC2-355E-45BA-B32C-D2C0A3811BB4/data/Containers/Data/Application/EDF3B7C8-A4BD-4629-813E-0934528AF02E/StoreKit/receipt
INFO: ℹ️ Receipt parsed successfully
INFO: ℹ️ Receipt content:
["inAppPurchases": [], "creationDate": 2022-09-21 21:00:07 +0000,
"opaqueValue": 8 bytes, "applicationVersion": "1",
"originalApplicationVersion": "<unknown>", "bundleId":
"com.revenuecat.StoreKitTestApp", "expirationDate": 4001-01-01 00:00:00
+0000, "sha1Hash": 20 bytes]
/Users/nachosoto/dev/purchases-ios/Tests/BackendIntegrationTests/StoreKitIntegrationTests.swift:64:
error: -[BackendIntegrationTests.StoreKit2IntegrationTests
testCanPurchaseProduct] : failed - Expected Entitlement. Got: [:]
expected to have Dictionary<String, EntitlementInfo> with count 1, got 0
Actual Value: [:]
I've also added the receipt as a test attachment so we can download it
from `CircleCI`:

2022-09-21 14:56:14 -07:00
aboedo
4d6c7bd5b8
More tests for receipt parsing with storekit test ( #1456 )
...
* made a few attributes that aren't present in SKTest receipts optional, added test with IAP
* added more tests for every field in the receipt
* fixed a few places where `asDict` wasn't correctly considering nullability in the IAP receipt fields
2022-04-06 15:44:00 -03:00
aboedo
fb193e37c8
Fix: ASN1 length calculation for indefinite-length ( #1452 )
...
* fixed length calculation for indefinite-length containers
* temporarily removed the early return from empty receipts
* fixed length calculation when parsing receipts with indefinite length
* fix linting
2022-04-06 11:02:59 -03:00
aboedo
cab0053885
Fix: local receipt parsing for StoreKitTest - part 1 ( #1446 )
...
* added basic ugly test
* fixed local receipt parsing for sktest, broke regular receipt parsing temporarily
* updated length calculation so that it works for both storekit test and regular receipts
* updated test to allow for missing OriginalAppVersion in receipt
* fixed linting in imports
* fixed checks for non-storekitTest receipts
* added a longer comment to explain the length == 0 case
* cleaned up the still-ugly tests for the receipt parser
2022-04-05 16:18:06 -03:00
aboedo
f5697de730
renamed Purchases folder to Sources ( #1416 )
...
* renamed `Purchases` folder to `Sources`
* temporarily enabling installation test jobs
* re-disabling installation test jobs
2022-03-28 11:53:24 -03:00