Skip to content

Trusted Entitlements: add support for signing request headers#3424

Merged
NachoSoto merged 7 commits into
mainfrom
trusted-entitlements-headers
Dec 21, 2023
Merged

Trusted Entitlements: add support for signing request headers#3424
NachoSoto merged 7 commits into
mainfrom
trusted-entitlements-headers

Conversation

@NachoSoto

@NachoSoto NachoSoto commented Nov 16, 2023

Copy link
Copy Markdown
Contributor

This adds support for including arbitrary headers in the signature verification, therefore preventing tampering of them.

@NachoSoto NachoSoto requested a review from a team November 16, 2023 19:25
@NachoSoto NachoSoto force-pushed the trusted-entitlements-headers branch from 03c29a7 to beb69fc Compare November 16, 2023 19:37
@NachoSoto NachoSoto changed the base branch from main to http-client-test-headers November 16, 2023 21:42
@NachoSoto NachoSoto force-pushed the trusted-entitlements-headers branch 2 times, most recently from 658c490 to b777a9f Compare November 16, 2023 21:47
@NachoSoto NachoSoto force-pushed the http-client-test-headers branch 2 times, most recently from 700fc54 to 50ad627 Compare November 16, 2023 23:07
@NachoSoto NachoSoto force-pushed the trusted-entitlements-headers branch from b777a9f to 958a5a9 Compare November 17, 2023 17:29

static func headerParametersForSignatureHeader(with headers: RequestHeaders) -> RequestHeaders {
if let header = HTTPRequest.headerParametersForSignatureHeader(headers: headers) {
return [RequestHeader.headerParametersForSignature.rawValue: header]

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.

This is tested by snapshot tests.

@NachoSoto NachoSoto force-pushed the http-client-test-headers branch from 26c660b to 5d0afcb Compare November 17, 2023 18:43
@NachoSoto NachoSoto force-pushed the trusted-entitlements-headers branch from 958a5a9 to 01268ef Compare November 17, 2023 20:00
Comment thread Tests/UnitTests/Mocks/MockHTTPClient.swift Outdated
Base automatically changed from http-client-test-headers to main November 17, 2023 20:19
NachoSoto added a commit that referenced this pull request Nov 17, 2023
This allows us to verify exactly what headers are included in all
requests.

It also simplifies the implementation for #3424.
@NachoSoto NachoSoto force-pushed the trusted-entitlements-headers branch from 01268ef to 7a2c93b Compare November 17, 2023 20:20
@NachoSoto NachoSoto force-pushed the trusted-entitlements-headers branch 3 times, most recently from 9ec2f4b to 132dca7 Compare December 8, 2023 19:23
NachoSoto added a commit that referenced this pull request Dec 8, 2023
…er hash

Follow up to #3424. This adds coverage to ensure that the backend continues to sign correctly for old SDK versions that don't support this.
@NachoSoto NachoSoto changed the title [WIP] Trusted Entitlements: add support for signing request headers Trusted Entitlements: add support for signing request headers Dec 8, 2023
@NachoSoto NachoSoto marked this pull request as ready for review December 8, 2023 20:39
}

@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *)
static func signingParameterHash(_ values: [String]) -> String {

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.

This is now a shared method for both POST body and header parameters.

nonce +
path +
postParameterHash +
headerParametersHash +

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.

Thanks to unit tests I was able to get this right. Initially I had this before the post hash.

let response = """
{"request_date":"2023-12-08T19:17:04Z","request_date_ms":1702063024731,"subscriber":{"entitlements":{},"first_seen":"2023-12-08T19:13:02Z","last_seen":"2023-12-08T19:13:02Z","management_url":null,"non_subscriptions":{},"original_app_user_id":"$RCAnonymousID:6ca4535c42714f88abc99c563703f113","original_application_version":null,"original_purchase_date":null,"other_purchases":{},"subscriptions":{}}}\n
"""
let expectedSignature = "x2qnlHOl5WuzGi4TbSUVHxzlKELRCfrRYG9XAiso7ucZTQAAYEZqbguA3X0YfCJqCKh2hnTLSdEr4R+t23xBlTxceWZu2TJjK3461UJKpUnrwXDv+tYo2K54IoS3/tsEr3VmB5ppKAq0P2CR7SwbsDPpxUlHBcl5/4XJvb/DHOnTKjIVd4WJ+57LLWvIV9sDHnj9XxiBez+p5cEjez1RtUis0XdCfAFXU8XfAq6ggiEJKX4F"

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.

I've generated these from the backend, so we can confirm that these real signatures are valid.

@NachoSoto NachoSoto force-pushed the trusted-entitlements-headers branch 2 times, most recently from 03c0f9f to ad9af4c Compare December 8, 2023 23:37
@NachoSoto NachoSoto force-pushed the trusted-entitlements-headers branch 2 times, most recently from 33a7047 to 26eb5bf Compare December 20, 2023 20:58
NachoSoto added a commit that referenced this pull request Dec 20, 2023
…er hash

Follow up to #3424. This adds coverage to ensure that the backend continues to sign correctly for old SDK versions that don't support this.
@NachoSoto NachoSoto force-pushed the trusted-entitlements-headers branch from 26eb5bf to 730c8b5 Compare December 20, 2023 21:07
NachoSoto added a commit that referenced this pull request Dec 20, 2023
…er hash

Follow up to #3424. This adds coverage to ensure that the backend continues to sign correctly for old SDK versions that don't support this.
@NachoSoto

Copy link
Copy Markdown
Contributor Author

This should be ready, but the signature is still wrong on the load shedder

@codecov

codecov Bot commented Dec 21, 2023

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 97.61905% with 2 lines in your changes missing coverage. Please review.

Project coverage is 86.02%. Comparing base (275e21b) to head (730c8b5).
Report is 384 commits behind head on main.

Files with missing lines Patch % Lines
Sources/Security/HTTPRequest+Signing.swift 95.55% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3424      +/-   ##
==========================================
+ Coverage   85.97%   86.02%   +0.05%     
==========================================
  Files         240      241       +1     
  Lines       17494    17552      +58     
==========================================
+ Hits        15040    15099      +59     
+ Misses       2454     2453       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@NachoSoto

Copy link
Copy Markdown
Contributor Author

Merging this! 🎉

@NachoSoto NachoSoto merged commit fb76e66 into main Dec 21, 2023
@NachoSoto NachoSoto deleted the trusted-entitlements-headers branch December 21, 2023 19:53
@NachoSoto NachoSoto removed the blocked label Dec 21, 2023
NachoSoto added a commit that referenced this pull request Dec 21, 2023
…er hash

Follow up to #3424. This adds coverage to ensure that the backend continues to sign correctly for old SDK versions that don't support this.
NachoSoto added a commit that referenced this pull request Dec 21, 2023
…er hash (#3505)

Follow up to #3424. This adds coverage to ensure that the backend
continues to sign correctly for old SDK versions that don't support
this.

@aboedo aboedo left a comment

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'm late to the game but great work on this!

NachoSoto pushed a commit that referenced this pull request Dec 22, 2023
**This is an automatic release.**

### RevenueCatUI
* `Paywalls`: add header image to `watchOS` paywalls (#3542) via
NachoSoto (@NachoSoto)
* `Paywalls`: improve template 5 landscape layout (#3534) via NachoSoto
(@NachoSoto)
* `Paywalls`: fix template 5 footer loading view alignment (#3537) via
NachoSoto (@NachoSoto)
* `Paywalls`: improve template 1 landscape layout (#3532) via NachoSoto
(@NachoSoto)
* `Paywalls`: fix `ColorInformation.multiScheme` on `watchOS` (#3530)
via NachoSoto (@NachoSoto)
### Other Changes
* `Trusted Entitlements`: tests for signature verification without
header hash (#3505) via NachoSoto (@NachoSoto)
* `.debugRevenueCatOverlay`: added `Locale` (#3539) via NachoSoto
(@NachoSoto)
* `Trusted Entitlements`: add support for signing request headers
(#3424) via NachoSoto (@NachoSoto)
* `CI`: Add architecture to cache keys (#3538) via Mark Villacampa
(@MarkVillacampa)
* `Paywalls Tester`: remove double close button (#3531) via NachoSoto
(@NachoSoto)
* Fix `RevenueCatUI` snapshot tests (#3526) via NachoSoto (@NachoSoto)
rickvdl added a commit that referenced this pull request May 28, 2026
…ad of Offering

Matches the Android PR #3424 changes:
- Replace `offering: Offering?` property with `@_spi(Internal) presentedOfferingContext`
  so the params object stores the derived context rather than the raw Offering
- Add `@_spi(Internal)` designated init for hybrid SDK (PHC) passthrough of
  pre-resolved presentedOfferingContext without requiring an Offering object
- Deprecate `init(paywallId:offeringId:)` in favour of `init(paywallId:offering:)`
- Update `trackCustomPaywallImpression` resolution order to match Android:
  params.presentedOfferingContext → cached[offeringId] → cached.current
- Update Swift and ObjC API testers accordingly
rickvdl added a commit that referenced this pull request Jun 1, 2026
…ad of Offering

Matches the Android PR #3424 changes:
- Replace `offering: Offering?` property with `@_spi(Internal) presentedOfferingContext`
  so the params object stores the derived context rather than the raw Offering
- Add `@_spi(Internal)` designated init for hybrid SDK (PHC) passthrough of
  pre-resolved presentedOfferingContext without requiring an Offering object
- Deprecate `init(paywallId:offeringId:)` in favour of `init(paywallId:offering:)`
- Update `trackCustomPaywallImpression` resolution order to match Android:
  params.presentedOfferingContext → cached[offeringId] → cached.current
- Update Swift and ObjC API testers accordingly
rickvdl added a commit that referenced this pull request Jun 1, 2026
* Add presented offering context to custom paywall events

* Update API testers for offering-based custom paywall impression init

* Add tests for placement and targeting in custom paywall events

* Accept Offering for custom paywall impression and derive context

* Decouple custom paywall wire request from PaywallEvent's nested context type

* Look up offeringId in cached offerings to derive presented offering context

* Update baseline swiftinterface files for `rickvdl/add-presented-offering-context-to-custom-paywall-events` (#6722)

* Add presented offering context to custom paywall events

* Update API testers for offering-based custom paywall impression init

* Add tests for placement and targeting in custom paywall events

* Accept Offering for custom paywall impression and derive context

* Decouple custom paywall wire request from PaywallEvent's nested context type

* Look up offeringId in cached offerings to derive presented offering context

* Update baseline swiftinterface files

---------

Co-authored-by: Rick van der Linden <rick.vanderlinden@revenuecat.com>

* Inline offering resolution as plain if-let in trackCustomPaywallImpression

* Fix race between init and applicationWillEnterForeground in TransactionMetadataSyncHelper

The syncIfNeeded call in Purchases.init races with the call from
applicationWillEnterForeground: if the init task acquires isSyncing first
(even with empty metadata), it blocks the foreground notification task
from running. Removing the init call is safe because applicationWillEnterForeground
fires reliably on startup and covers the sync need.

* Revert "Fix race between init and applicationWillEnterForeground in TransactionMetadataSyncHelper"

This reverts commit d977926.

* Align CustomPaywallImpressionParams with Android: store context instead of Offering

Matches the Android PR #3424 changes:
- Replace `offering: Offering?` property with `@_spi(Internal) presentedOfferingContext`
  so the params object stores the derived context rather than the raw Offering
- Add `@_spi(Internal)` designated init for hybrid SDK (PHC) passthrough of
  pre-resolved presentedOfferingContext without requiring an Offering object
- Deprecate `init(paywallId:offeringId:)` in favour of `init(paywallId:offering:)`
- Update `trackCustomPaywallImpression` resolution order to match Android:
  params.presentedOfferingContext → cached[offeringId] → cached.current
- Update Swift and ObjC API testers accordingly

* Fix lint: suppress line_length for @available deprecated message

* Remove params.offering tests — property replaced by presentedOfferingContext

* Update baseline swiftinterface files (#6864)

* Include placement and targeting in custom paywall event map

---------

Co-authored-by: RevenueCat Git Bot <72824662+RCGitBot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants