Skip to content

Update CustomerInfo.requestDate from 304 responses#2310

Merged
NachoSoto merged 2 commits into
mainfrom
nacho/sdk-2856-requestdate-not-returning-updated-value
Mar 1, 2023
Merged

Update CustomerInfo.requestDate from 304 responses#2310
NachoSoto merged 2 commits into
mainfrom
nacho/sdk-2856-requestdate-not-returning-updated-value

Conversation

@NachoSoto

@NachoSoto NachoSoto commented Feb 21, 2023

Copy link
Copy Markdown
Contributor

Purpose:

This is a prerequisite for #2288. The new grace period means that if we didn't update the date from the cached responses, entitlements would become stale and expired after 3 days.

Changes:

  • Added HTTPResponseBody.copy(with newRequestDate:) to be able to modify responses from the header request date
  • CustomerInfo implements this method to modify its request date
  • Added HTTPResponse.requestDate to be able to keep track of the request date from the server
  • Added VerificationResult.from(cache:response:) to determine the most restrictive verification result based on what's cached or checked from a response
  • Added HTTPResponse.copy(with:) to modify the verification result of a response using the previous method
  • HTTPClient now uses the most restrictive verification result
  • HTTPClient updates request date from server responses or cached responses (unless verification failed). This was the missing piece for EntitlementInfo: add a grace period limit to outdated entitlements #2288.

Tests:

  • Verify that ETagManager does not use an ETag if verification was previously not enabled
  • Verify that ETagManager returns the request date from the server when returning a cached response
  • Verify that HTTPClient updates the request date from the server or from a cached response
  • Verify that HTTPClient does not update request date if verification failed
  • Tests for HTTPResponse request date parsing
  • Test for CustomerInfoResponseHandler updating request date
  • Tests for CustomerInfo.copy(with newRequestDate:)

Other smaller changes:

  • Moved CustomerInfo.asData() into Encodable.asJSONEncodedData()
  • Renamed requestTime to requestDate everywhere for consistency

@NachoSoto NachoSoto requested a review from a team February 21, 2023 22:03
@NachoSoto NachoSoto force-pushed the nacho/sdk-2856-requestdate-not-returning-updated-value branch from 8070e78 to fb31138 Compare February 21, 2023 22:04
@NachoSoto NachoSoto force-pushed the nacho/sdk-2914-update-signature-to-include-timestamp branch from 0b95ec2 to 405c654 Compare February 21, 2023 22:55
@NachoSoto NachoSoto closed this Feb 21, 2023
@NachoSoto NachoSoto deleted the nacho/sdk-2856-requestdate-not-returning-updated-value branch February 21, 2023 23:00
@NachoSoto NachoSoto restored the nacho/sdk-2856-requestdate-not-returning-updated-value branch February 21, 2023 23:02
@NachoSoto NachoSoto reopened this Feb 21, 2023
@NachoSoto NachoSoto removed the blocked label Feb 21, 2023
@NachoSoto NachoSoto force-pushed the nacho/sdk-2856-requestdate-not-returning-updated-value branch from fb31138 to 07fff48 Compare February 21, 2023 23:07
@NachoSoto NachoSoto changed the title CustomerInfo: get requestDate from HTTPResponse header Update CustomerInfo.requestTime from 304 responses Feb 21, 2023
@NachoSoto NachoSoto force-pushed the nacho/sdk-2914-update-signature-to-include-timestamp branch 7 times, most recently from e228f72 to 59cdce7 Compare February 27, 2023 16:58
Base automatically changed from nacho/sdk-2914-update-signature-to-include-timestamp to main February 27, 2023 17:07
@NachoSoto NachoSoto force-pushed the nacho/sdk-2856-requestdate-not-returning-updated-value branch 4 times, most recently from f15a7d0 to 648de65 Compare February 27, 2023 20:29
@NachoSoto NachoSoto changed the title Update CustomerInfo.requestTime from 304 responses Update CustomerInfo.requestDate from 304 responses Feb 27, 2023
@NachoSoto NachoSoto force-pushed the nacho/sdk-2856-requestdate-not-returning-updated-value branch 3 times, most recently from 335d4e2 to ff74ab4 Compare February 27, 2023 21:12
@NachoSoto NachoSoto force-pushed the nacho/sdk-2856-requestdate-not-returning-updated-value branch 2 times, most recently from 58e5366 to 843b6c3 Compare February 28, 2023 00:03
@NachoSoto NachoSoto removed the WIP label Feb 28, 2023
@NachoSoto NachoSoto force-pushed the nacho/sdk-2856-requestdate-not-returning-updated-value branch from 843b6c3 to d50f942 Compare February 28, 2023 00:20
@NachoSoto NachoSoto marked this pull request as ready for review February 28, 2023 00:20
### Changes:
- Added `HTTPResponseBody.copy(with newRequestDate:)` to be able to modify responses from the header request date
- `CustomerInfo` implements this method to modify its request date
- Added `HTTPResponse.requestDate` to be able to keep track of the request date from the server
- Added `VerificationResult.from(cache:response:)` to determine the most restrictive verification result based on what's cached or checked from a response
- Added `HTTPResponse.copy(with:)` to modify the verification result of a response using the previous method
- `HTTPClient` now uses the most restrictive verification result
- `HTTPClient` updates request date from server responses or cached responses (unless verification failed). This was the missing piece for #2288.

### Tests:
- Verify that `ETagManager` does not use an ETag if verification was previously not enabled
- Verify that `ETagManager` returns the request date from the server when returning a cached response
- Verify that `HTTPClient` updates the request date from the server or from a cached response
- Verify that `HTTPClient` does not update request date if verification failed
- Tests for `HTTPResponse` request date parsing
- Test for `CustomerInfoResponseHandler` updating request date
- Tests for `CustomerInfo.copy(with newRequestDate:)`

### Other smaller changes:
- Moved `CustomerInfo.asData()` into `Encodable.asJSONEncodedData()`
- Renamed `requestTime` to `requestDate` everywhere for consistency
@NachoSoto NachoSoto force-pushed the nacho/sdk-2856-requestdate-not-returning-updated-value branch from d50f942 to 7a2204d Compare February 28, 2023 00:24
@codecov

codecov Bot commented Feb 28, 2023

Copy link
Copy Markdown

Codecov Report

Merging #2310 (7a2204d) into main (b707f8a) will increase coverage by 0.04%.
The diff coverage is 100.00%.

❗ Current head 7a2204d differs from pull request most recent head 27920fa. Consider uploading reports for the commit 27920fa to get more accurate results

@@            Coverage Diff             @@
##             main    #2310      +/-   ##
==========================================
+ Coverage   86.41%   86.45%   +0.04%     
==========================================
  Files         187      188       +1     
  Lines       12630    12714      +84     
==========================================
+ Hits        10914    10992      +78     
- Misses       1716     1722       +6     
Impacted Files Coverage Δ
Sources/FoundationExtensions/Date+Extensions.swift 100.00% <100.00%> (ø)
Sources/Identity/CustomerInfo.swift 89.53% <100.00%> (+0.44%) ⬆️
Sources/Logging/Strings/CustomerInfoStrings.swift 92.68% <100.00%> (+0.37%) ⬆️
Sources/Logging/Strings/SigningStrings.swift 95.00% <100.00%> (ø)
Sources/Misc/Signing+ResponseVerification.swift 98.01% <100.00%> (+0.40%) ⬆️
Sources/Misc/Signing.swift 88.76% <100.00%> (ø)
Sources/Networking/HTTPClient/ETagManager.swift 99.19% <100.00%> (+<0.01%) ⬆️
Sources/Networking/HTTPClient/HTTPClient.swift 98.20% <100.00%> (+0.09%) ⬆️
Sources/Networking/HTTPClient/HTTPResponse.swift 93.75% <100.00%> (+0.58%) ⬆️
...urces/Networking/HTTPClient/HTTPResponseBody.swift 100.00% <100.00%> (ø)
... and 8 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

@tonidero tonidero left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a possible edge case I was thinking about but looking great!

Comment thread Sources/Purchasing/VerificationResult.swift
let path: HTTPRequest.Path = .mockPath
let mockedResponse = BodyWithDate(data: "test", requestDate: Date().addingTimeInterval(-3000000))
let encodedResponse = try mockedResponse.asJSONEncodedData()
let requestDate = Date().addingTimeInterval(-100000)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do these numbers mean? We could also hardcode a date for this and the mockedResponse request date to make it more deterministic.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's just a simpler way to make a date that's not "now" to avoid false negatives.

Comment thread Tests/UnitTests/Networking/HTTPClientTests.swift
@bisho

bisho commented Feb 28, 2023

Copy link
Copy Markdown
Member

Can you add a test in case the server returns a 500 error? Want to ensure that is not treated as verification failure even if the date header is not present.

Comment on lines +193 to 194
requestDate: requestDate,
verificationResult: self.verificationResult

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should only update the requestDate if the verification result of the NOT_MODIFIED response is green, right?

@bisho bisho Feb 28, 2023

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And do we persist this date change in the cache?
Imagine:

  1. 200 OK, valid signature, with request time t=1. SDK gets (valid signature, t=1)
  2. 304 NOT_MODIFIED, valid signature, with request time t=2. SDK gets (valid signature, t=2)
  3. Timeout or error 500... What the SDK will retrieve t=1 or t=2?. Should be (valid signature, t=2)

@bisho bisho Feb 28, 2023

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly:

  1. 200 OK, valid signature with request time t=1. SDK gets (valid signature, t=1)
  2. 304 NOT_MODIFIED, INVALID signature, with request time t=2. SDK should get (valid signature, t=1)
  3. Timeout or error 500, SDK should get (valid signature, t=1)

And:

  1. 200 OK valid signature, t=1. SDK gets (valid signature, t=1)
  2. 200 OK INVALID SIGNATURE, t=2. SDK gets (valid signature, t=1)
  3. Timeout or error 500, SDK should get (valid signature, t=1)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nacho can correct me but I believe we currently cache the request time not at the response level but at the model level. Right now we only cache it for the CustomerInfo model so we only store it in those models. We don't update the response cache on not modified responses either

@NachoSoto NachoSoto Feb 28, 2023

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Timeout or error 500... What the SDK will retrieve t=1 or t=2?. Should be (valid signature, t=2)

Short answer is t2.

@bisho you're conflating 2 separate layers of caching (which is normal because you're not familiar with the codebase).

If the server fails to return a 304 (500 or timeout), HTTPClient won't return the cached data.
That caching would be handled by DeviceCache, which would receive the updated request time.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should only update the requestDate if the verification result of the NOT_MODIFIED response is green, right?

That I think I have a test for but let me check.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

304 NOT_MODIFIED, INVALID signature, with request time t=2. SDK should get (valid signature, t=1)

Oh that's a case I didn't consider.
Are we sure we want to do that? That would break an app without any indication that this is happening.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should only update the requestDate if the verification result of the NOT_MODIFIED response is green, right?

That's already done:

fileprivate func copyWithNewRequestDate() -> Self {
    // Update request time from server unless it failed verification.
    guard self.verificationResult != .failed, let requestDate = self.requestDate else { return self }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

304 NOT_MODIFIED, INVALID signature, with request time t=2. SDK should get (valid signature, t=1)

Oh that's a case I didn't consider.
Are we sure we want to do that? That would break an app without any indication that this is happening.

The thing is that you can't use t=2 as it is not verified. And making the cache not verified in whole defeats the purpose of the cache. Note that there are legit cases of tampering (you are in an airport wifi that intercepts HTTPs. So you can't assume it is a bad actor and use t=2 but making it fail validation. We have a cache, use it until you can. The only case for using t=2 is if there app has disabled verification.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that we can't use t=2, otherwise that opens us up to an easy attack.

But I'm not sure about the part about considering any result that we have "verified" if we get a signature that we can't verify - even if it's from a 304. Like, "someone told us to use what's in cache but we don't really trust them" seems like a clear use case for "not verified".

I get that we're not entirely sure if any valid tampering will happen in real life, but... this is all happening at the application level, right? Like, there really shouldn't be any modified content in the response content, datetime or request uuid that a public wifi modifies to have us fail validation.

It feels like we might be setting ourselves up for one of those use cases that takes a long time to explain to someone, while just saying "if you got an invalid signature, you get an unverified entitlement" seems a lot simpler


/// - Returns: the most restrictive ``VerificationResult`` based on the cached verification and
/// the response verification.
static func from(cache cachedResult: Self, response responseResult: Self) -> Self {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see that here you will return the response as not valid if a 304 is not valid. I don't think we should do this. We should act as unable to fetch. There is a legit situation for this, imagine you are in a airport wifi that intercepts and mangles requests. It should not break your cache.

I think I still have trouble with the logic for validation being in two places.

I would rather do something like:

  • For validation errors (either 200, 403...), if there is cache, treat this as a 500, just return cache
  • For 403 update request time in cache only if cache was checked valid and 304 was valid too (304 invalid would be covered in the above case anyway). Then return cache.
  • For valid 200, update cache, return fresh data

Pseudocode:

# On requests:
if cache and (cacheValidationOk or SDKValidationDisabled):
    request_with_cache_etag()
else:
    request_without_etag()
def get_response_or_cache():
# On responses:
wrong_response = response_not_modified and (we_did_not_sent_etag or returned_etag_mistmatch)
  return FailedRequest  # This should not happen, we only expect not modified if we have a etag cached reponse. If the cache data is not trusted we should NOT send etag always to force a refetch (unless SDKValidationDisabled).

if failedRequest or wrong_response:
    if cache:
        return cache
    else:
        return FailedRequest

trust_response = responseValidationOk or SDKValidationDisabled

if trust_response:
    if not_modified:
        update_cache_request_time()
        # While we might trust the response if validation is disabled, we still track
        # wether the cached data is valid or not, and it will be only valid if cache
        # and requests are both valid
        update_cache_validation_to(responseValidationOk and cacheValidationOk)
        return cache
    else:
        store_new_response_in_cache()
        update_cache_validation_to(responseValidationOk)
        return response
elif cacheValidationOk:
    # If we are not trusting response, prefer valid cache always
    return cache
else:
    # We do not trust response nor cache
    if not_modified:
        return cache
    else:
        store_new_response_in_cache()
        update_cache_validation_to(validationFailed)
        return response

This code will handle properly the cache and validation status. In some cases this will return responses with validation failures, but it will try its best to use valid cache over a failed validation response (unless we are using the disable validation mode, in which case uses all responses valid or not (but still tracks validation state irregardless).

Above this, you can put the enforcer layer for strict mode. Having it separate simplifies the request / cache mangling layer.

    response = get_response_or_cache()
    if SDKValidationStrictMode and not response.isValid:
        return failedValidation
    return response

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It took me a full hour write what I was thinking was going to be simple pseudocode. This request handling logic is truly complicated XDDD

Perhaps it is better to sync. Ping me if you are available.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see that here you will return the response as not valid if a 304 is not valid. I don't think we should do this. We should act as unable to fetch. There is a legit situation for this, imagine you are in an airport wifi that intercepts and mangles requests. It should not break your cache.

I think I still have trouble with the logic for validation being in two places.

I would rather do something like:

For validation errors (either 200, 403...), if there is cache, treat this as a 500, just return cache

That's not changed. As per my other comment, that would be handled by DeviceCache. HTTPClient doesn't return a valid response if there is a 500.

For 403 update request time in cache only if cache was checked valid and 304 was valid too (304 invalid would be covered in the above case anyway). Then return cache.
For valid 200, update cache, return fresh data

That's how it works 👍🏻

@NachoSoto

NachoSoto commented Mar 1, 2023

Copy link
Copy Markdown
Contributor Author

Can you add a test in case the server returns a 500 error?

We already have a test for that and it's still passing 👍🏻 (HTTPClient has 64 tests so it's pretty well covered).

@NachoSoto

Copy link
Copy Markdown
Contributor Author

I think I handled all comments, but let me know if I missed something.

@NachoSoto NachoSoto enabled auto-merge (squash) March 1, 2023 17:16
@NachoSoto NachoSoto merged commit da9ba39 into main Mar 1, 2023
@NachoSoto NachoSoto deleted the nacho/sdk-2856-requestdate-not-returning-updated-value branch March 1, 2023 17:24
@NachoSoto NachoSoto mentioned this pull request Mar 14, 2023
@NachoSoto

Copy link
Copy Markdown
Contributor Author

This fixes #2470.

@NachoSoto NachoSoto mentioned this pull request May 15, 2023
NachoSoto added a commit that referenced this pull request May 16, 2023
### New Features
* New `ErrorCode.signatureVerificationFailed` which will be used for an
upcoming feature

### Bugfixes
* `Purchases.deinit`: don't reset `Purchases.proxyURL` (#2346) via
NachoSoto (@NachoSoto)

<details>
<summary><b>Other Changes</b></summary>

* Introduced `Configuration.EntitlementVerificationMode` and
`VerificationResult` (#2277) via NachoSoto (@NachoSoto)
* `PurchasesDiagnostics`: added step to verify signature verification
(#2267) via NachoSoto (@NachoSoto)
* `HTTPClient`: added signature validation and introduced
`ErrorCode.signatureVerificationFailed` (#2272) via NachoSoto
(@NachoSoto)
* `ETagManager`: don't use ETags if response verification failed (#2347)
via NachoSoto (@NachoSoto)
* `Integration Tests`: removed `@preconcurrency import` (#2464) via
NachoSoto (@NachoSoto)
* Clean up: moved `ReceiptParserTests-Info.plist` out of root (#2460)
via NachoSoto (@NachoSoto)
* Update `CHANGELOG` (#2461) via NachoSoto (@NachoSoto)
* Update `SwiftSnapshotTesting` (#2453) via NachoSoto (@NachoSoto)
* Fixed docs (#2432) via Kaunteya Suryawanshi (@kaunteya)
* Remove unnecessary line break (#2435) via Andy Boedo (@aboedo)
* `ProductEntitlementMapping`: enabled entitlement mapping fetching
(#2425) via NachoSoto (@NachoSoto)
* `BackendPostReceiptDataTests`: increased timeout to fix flaky test
(#2426) via NachoSoto (@NachoSoto)
* Updated requirements to drop Xcode 13.x support (#2419) via NachoSoto
(@NachoSoto)
* `Integration Tests`: fixed flaky errors when loading offerings (#2420)
via NachoSoto (@NachoSoto)
* `PurchaseTester`: fixed compilation for `internal` entitlement
verification (#2417) via NachoSoto (@NachoSoto)
* `ETagManager`/`HTTPClient`: sending new `X-RC-Last-Refresh-Time`
header (#2373) via NachoSoto (@NachoSoto)
* `ETagManager`: don't send validation time if not present (#2490) via
NachoSoto (@NachoSoto)
* SwiftUI Sample Project: Refactor Package terms method to a computed
property (#2405) via Joseph Kokenge (@JOyo246)
* Clean up v3 load shedder integration tests (#2402) via Andy Boedo
(@aboedo)
* Fix iOS 12 compilation (#2394) via NachoSoto (@NachoSoto)
* Added new `VerificationResult.verifiedOnDevice` (#2379) via NachoSoto
(@NachoSoto)
* `PurchaseTester`: fix memory leaks (#2392) via Keita Watanabe
(@kitwtnb)
* Integration tests: add scheduled job (#2389) via Andy Boedo (@aboedo)
* Add lane for running iOS v3 load shedder integration tests (#2388) via
Andy Boedo (@aboedo)
* iOS v3 load shedder integration tests (#2387) via Andy Boedo (@aboedo)
* `Offline Entitlements`: created `LoadShedderIntegrationTests` (#2362)
via NachoSoto (@NachoSoto)
* Purchases.configure: log warning if attempting to use a static
appUserID (#2385) via Mark Villacampa (@MarkVillacampa)
* `SubscriberAttributesManagerIntegrationTests`: fixed flaky failures
(#2381) via NachoSoto (@NachoSoto)
* `@DefaultDecodable.Now`: fixed flaky test (#2374) via NachoSoto
(@NachoSoto)
* `PurchaseTesterSwiftUI`: fixed iOS compilation (#2376) via NachoSoto
(@NachoSoto)
* `SubscriberAttributesManagerIntegrationTests`: fixed potential race
condition (#2380) via NachoSoto (@NachoSoto)
* `Offline Entitlements`: create `CustomerInfo` from offline
entitlements (#2358) via NachoSoto (@NachoSoto)
* Added `@DefaultDecodable.Now` (#2372) via NachoSoto (@NachoSoto)
* `HTTPClient`: debug log when performing redirects (#2371) via
NachoSoto (@NachoSoto)
* `HTTPClient`: new flag to force server errors (#2370) via NachoSoto
(@NachoSoto)
* `OfferingsManager`: fixed Xcode 13.x build (#2369) via NachoSoto
(@NachoSoto)
* `Offline Entitlements`: store `ProductEntitlementMapping` in cache
(#2355) via NachoSoto (@NachoSoto)
* `Offline Entitlements`: added support for fetching
`ProductEntitlementMappingResponse` in `OfflineEntitlementsAPI` (#2353)
via NachoSoto (@NachoSoto)
* `Offline Entitlements`: created `ProductEntitlementMapping` (#2365)
via NachoSoto (@NachoSoto)
* Implemented `NetworkError.isServerDown` (#2367) via NachoSoto
(@NachoSoto)
* `ETagManager`: added test for 304 responses with no etag (#2360) via
NachoSoto (@NachoSoto)
* `TestLogHandler`: increased default capacity (#2357) via NachoSoto
(@NachoSoto)
* `OfferingsManager`: moved log to common method to remove hardcoded
string (#2363) via NachoSoto (@NachoSoto)
* `Offline Entitlements`: created `ProductEntitlementMappingResponse`
(#2351) via NachoSoto (@NachoSoto)
* `HTTPClient`: added test for 2xx response for request with etag
(#2361) via NachoSoto (@NachoSoto)
* `PurchaseTesterSwiftUI` improvements (#2345) via NachoSoto
(@NachoSoto)
* `ConfigureStrings`: fixed double-space typo (#2344) via NachoSoto
(@NachoSoto)
* `ETagManagerTests`: fixed tests on iOS 12 (#2349) via NachoSoto
(@NachoSoto)
* `DeviceCache`: simplified constructor (#2354) via NachoSoto
(@NachoSoto)
* `Trusted Entitlements`: changed all APIs to `internal` (#2350) via
NachoSoto (@NachoSoto)
* `VerificationResult.notRequested`: removed caching reference (#2337)
via NachoSoto (@NachoSoto)
* Finished signature verification `HTTPClient` tests (#2333) via
NachoSoto (@NachoSoto)
* `Configuration.Builder.with(entitlementVerificationMode:)`: improved
documentation (#2334) via NachoSoto (@NachoSoto)
* `ETagManager`: don't ignore failed etags with
`Signing.VerificationMode.informational` (#2331) via NachoSoto
(@NachoSoto)
* `IdentityManager`: clear `ETagManager` and `DeviceCache` if
verification is enabled but cached `CustomerInfo` is not (#2330) via
NachoSoto (@NachoSoto)
* Made `Configuration.EntitlementVerificationMode.enforced` unavailable
(#2329) via NachoSoto (@NachoSoto)
* Refactor: reorganized files in new Security and Misc folders (#2326)
via NachoSoto (@NachoSoto)
* `CustomerInfo`: use same grace period logic for active subscriptions
(#2327) via NachoSoto (@NachoSoto)
* `HTTPClient`: don't verify 4xx/5xx responses (#2322) via NachoSoto
(@NachoSoto)
* `EntitlementInfo`: request date is not optional (#2325) via NachoSoto
(@NachoSoto)
* `CustomerInfo`: removed `entitlementVerification` (#2320) via
NachoSoto (@NachoSoto)
* Renamed `VerificationResult.notVerified` to `.notRequested` (#2321)
via NachoSoto (@NachoSoto)
* `EntitlementInfo`: add a grace period limit to outdated entitlements
(#2288) via NachoSoto (@NachoSoto)
* Update `CustomerInfo.requestDate` from 304 responses (#2310) via
NachoSoto (@NachoSoto)
* `Signing`: added request time & eTag to signature verification (#2309)
via NachoSoto (@NachoSoto)
* `HTTPClient`: changed header search to be case-insensitive (#2308) via
NachoSoto (@NachoSoto)
* `HTTPClient`: automatically add `nonce` based on `HTTPRequest.Path`
(#2286) via NachoSoto (@NachoSoto)
* `PurchaseTester`: added ability to reload `CustomerInfo` with a custom
`CacheFetchPolicy` (#2312) via NachoSoto (@NachoSoto)
* Fix issue where underlying error information for product fetch errors
was not printed in log. (#2281) via Chris Vasselli (@chrisvasselli)
* `PurchaseTester`: added ability to set
`Configuration.EntitlementVerificationMode` (#2290) via NachoSoto
(@NachoSoto)
* SwiftUI: Paywall View should respond to changes on the UserView model
(#2297) via ConfusedVorlon (@ConfusedVorlon)
* Deprecate `usesStoreKit2IfAvailable` (#2293) via Andy Boedo (@aboedo)
* `Signing`: updated to use production public key (#2274) via NachoSoto
(@NachoSoto)
</details>

---------

Co-authored-by: RCGitBot <dev+RCGitBot@revenuecat.com>
NachoSoto added a commit to NachoSoto/purchases-ios that referenced this pull request May 17, 2023
### New Features
* New `ErrorCode.signatureVerificationFailed` which will be used for an
upcoming feature

### Bugfixes
* `Purchases.deinit`: don't reset `Purchases.proxyURL` (RevenueCat#2346) via
NachoSoto (@NachoSoto)

<details>
<summary><b>Other Changes</b></summary>

* Introduced `Configuration.EntitlementVerificationMode` and
`VerificationResult` (RevenueCat#2277) via NachoSoto (@NachoSoto)
* `PurchasesDiagnostics`: added step to verify signature verification
(RevenueCat#2267) via NachoSoto (@NachoSoto)
* `HTTPClient`: added signature validation and introduced
`ErrorCode.signatureVerificationFailed` (RevenueCat#2272) via NachoSoto
(@NachoSoto)
* `ETagManager`: don't use ETags if response verification failed (RevenueCat#2347)
via NachoSoto (@NachoSoto)
* `Integration Tests`: removed `@preconcurrency import` (RevenueCat#2464) via
NachoSoto (@NachoSoto)
* Clean up: moved `ReceiptParserTests-Info.plist` out of root (RevenueCat#2460)
via NachoSoto (@NachoSoto)
* Update `CHANGELOG` (RevenueCat#2461) via NachoSoto (@NachoSoto)
* Update `SwiftSnapshotTesting` (RevenueCat#2453) via NachoSoto (@NachoSoto)
* Fixed docs (RevenueCat#2432) via Kaunteya Suryawanshi (@kaunteya)
* Remove unnecessary line break (RevenueCat#2435) via Andy Boedo (@aboedo)
* `ProductEntitlementMapping`: enabled entitlement mapping fetching
(RevenueCat#2425) via NachoSoto (@NachoSoto)
* `BackendPostReceiptDataTests`: increased timeout to fix flaky test
(RevenueCat#2426) via NachoSoto (@NachoSoto)
* Updated requirements to drop Xcode 13.x support (RevenueCat#2419) via NachoSoto
(@NachoSoto)
* `Integration Tests`: fixed flaky errors when loading offerings (RevenueCat#2420)
via NachoSoto (@NachoSoto)
* `PurchaseTester`: fixed compilation for `internal` entitlement
verification (RevenueCat#2417) via NachoSoto (@NachoSoto)
* `ETagManager`/`HTTPClient`: sending new `X-RC-Last-Refresh-Time`
header (RevenueCat#2373) via NachoSoto (@NachoSoto)
* `ETagManager`: don't send validation time if not present (RevenueCat#2490) via
NachoSoto (@NachoSoto)
* SwiftUI Sample Project: Refactor Package terms method to a computed
property (RevenueCat#2405) via Joseph Kokenge (@JOyo246)
* Clean up v3 load shedder integration tests (RevenueCat#2402) via Andy Boedo
(@aboedo)
* Fix iOS 12 compilation (RevenueCat#2394) via NachoSoto (@NachoSoto)
* Added new `VerificationResult.verifiedOnDevice` (RevenueCat#2379) via NachoSoto
(@NachoSoto)
* `PurchaseTester`: fix memory leaks (RevenueCat#2392) via Keita Watanabe
(@kitwtnb)
* Integration tests: add scheduled job (RevenueCat#2389) via Andy Boedo (@aboedo)
* Add lane for running iOS v3 load shedder integration tests (RevenueCat#2388) via
Andy Boedo (@aboedo)
* iOS v3 load shedder integration tests (RevenueCat#2387) via Andy Boedo (@aboedo)
* `Offline Entitlements`: created `LoadShedderIntegrationTests` (RevenueCat#2362)
via NachoSoto (@NachoSoto)
* Purchases.configure: log warning if attempting to use a static
appUserID (RevenueCat#2385) via Mark Villacampa (@MarkVillacampa)
* `SubscriberAttributesManagerIntegrationTests`: fixed flaky failures
(RevenueCat#2381) via NachoSoto (@NachoSoto)
* `@DefaultDecodable.Now`: fixed flaky test (RevenueCat#2374) via NachoSoto
(@NachoSoto)
* `PurchaseTesterSwiftUI`: fixed iOS compilation (RevenueCat#2376) via NachoSoto
(@NachoSoto)
* `SubscriberAttributesManagerIntegrationTests`: fixed potential race
condition (RevenueCat#2380) via NachoSoto (@NachoSoto)
* `Offline Entitlements`: create `CustomerInfo` from offline
entitlements (RevenueCat#2358) via NachoSoto (@NachoSoto)
* Added `@DefaultDecodable.Now` (RevenueCat#2372) via NachoSoto (@NachoSoto)
* `HTTPClient`: debug log when performing redirects (RevenueCat#2371) via
NachoSoto (@NachoSoto)
* `HTTPClient`: new flag to force server errors (RevenueCat#2370) via NachoSoto
(@NachoSoto)
* `OfferingsManager`: fixed Xcode 13.x build (RevenueCat#2369) via NachoSoto
(@NachoSoto)
* `Offline Entitlements`: store `ProductEntitlementMapping` in cache
(RevenueCat#2355) via NachoSoto (@NachoSoto)
* `Offline Entitlements`: added support for fetching
`ProductEntitlementMappingResponse` in `OfflineEntitlementsAPI` (RevenueCat#2353)
via NachoSoto (@NachoSoto)
* `Offline Entitlements`: created `ProductEntitlementMapping` (RevenueCat#2365)
via NachoSoto (@NachoSoto)
* Implemented `NetworkError.isServerDown` (RevenueCat#2367) via NachoSoto
(@NachoSoto)
* `ETagManager`: added test for 304 responses with no etag (RevenueCat#2360) via
NachoSoto (@NachoSoto)
* `TestLogHandler`: increased default capacity (RevenueCat#2357) via NachoSoto
(@NachoSoto)
* `OfferingsManager`: moved log to common method to remove hardcoded
string (RevenueCat#2363) via NachoSoto (@NachoSoto)
* `Offline Entitlements`: created `ProductEntitlementMappingResponse`
(RevenueCat#2351) via NachoSoto (@NachoSoto)
* `HTTPClient`: added test for 2xx response for request with etag
(RevenueCat#2361) via NachoSoto (@NachoSoto)
* `PurchaseTesterSwiftUI` improvements (RevenueCat#2345) via NachoSoto
(@NachoSoto)
* `ConfigureStrings`: fixed double-space typo (RevenueCat#2344) via NachoSoto
(@NachoSoto)
* `ETagManagerTests`: fixed tests on iOS 12 (RevenueCat#2349) via NachoSoto
(@NachoSoto)
* `DeviceCache`: simplified constructor (RevenueCat#2354) via NachoSoto
(@NachoSoto)
* `Trusted Entitlements`: changed all APIs to `internal` (RevenueCat#2350) via
NachoSoto (@NachoSoto)
* `VerificationResult.notRequested`: removed caching reference (RevenueCat#2337)
via NachoSoto (@NachoSoto)
* Finished signature verification `HTTPClient` tests (RevenueCat#2333) via
NachoSoto (@NachoSoto)
* `Configuration.Builder.with(entitlementVerificationMode:)`: improved
documentation (RevenueCat#2334) via NachoSoto (@NachoSoto)
* `ETagManager`: don't ignore failed etags with
`Signing.VerificationMode.informational` (RevenueCat#2331) via NachoSoto
(@NachoSoto)
* `IdentityManager`: clear `ETagManager` and `DeviceCache` if
verification is enabled but cached `CustomerInfo` is not (RevenueCat#2330) via
NachoSoto (@NachoSoto)
* Made `Configuration.EntitlementVerificationMode.enforced` unavailable
(RevenueCat#2329) via NachoSoto (@NachoSoto)
* Refactor: reorganized files in new Security and Misc folders (RevenueCat#2326)
via NachoSoto (@NachoSoto)
* `CustomerInfo`: use same grace period logic for active subscriptions
(RevenueCat#2327) via NachoSoto (@NachoSoto)
* `HTTPClient`: don't verify 4xx/5xx responses (RevenueCat#2322) via NachoSoto
(@NachoSoto)
* `EntitlementInfo`: request date is not optional (RevenueCat#2325) via NachoSoto
(@NachoSoto)
* `CustomerInfo`: removed `entitlementVerification` (RevenueCat#2320) via
NachoSoto (@NachoSoto)
* Renamed `VerificationResult.notVerified` to `.notRequested` (RevenueCat#2321)
via NachoSoto (@NachoSoto)
* `EntitlementInfo`: add a grace period limit to outdated entitlements
(RevenueCat#2288) via NachoSoto (@NachoSoto)
* Update `CustomerInfo.requestDate` from 304 responses (RevenueCat#2310) via
NachoSoto (@NachoSoto)
* `Signing`: added request time & eTag to signature verification (RevenueCat#2309)
via NachoSoto (@NachoSoto)
* `HTTPClient`: changed header search to be case-insensitive (RevenueCat#2308) via
NachoSoto (@NachoSoto)
* `HTTPClient`: automatically add `nonce` based on `HTTPRequest.Path`
(RevenueCat#2286) via NachoSoto (@NachoSoto)
* `PurchaseTester`: added ability to reload `CustomerInfo` with a custom
`CacheFetchPolicy` (RevenueCat#2312) via NachoSoto (@NachoSoto)
* Fix issue where underlying error information for product fetch errors
was not printed in log. (RevenueCat#2281) via Chris Vasselli (@chrisvasselli)
* `PurchaseTester`: added ability to set
`Configuration.EntitlementVerificationMode` (RevenueCat#2290) via NachoSoto
(@NachoSoto)
* SwiftUI: Paywall View should respond to changes on the UserView model
(RevenueCat#2297) via ConfusedVorlon (@ConfusedVorlon)
* Deprecate `usesStoreKit2IfAvailable` (RevenueCat#2293) via Andy Boedo (@aboedo)
* `Signing`: updated to use production public key (RevenueCat#2274) via NachoSoto
(@NachoSoto)
</details>

---------

Co-authored-by: RCGitBot <dev+RCGitBot@revenuecat.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants