See https://github.com/RevenueCat/khepri/pull/6798.
This can help debug issues as it helps us cross-reference requests on
our end.
### Changes:
- Logging `X-Request-ID` and `X-Amzn-Trace-ID` headers if present (only
in verbose mode)
- Logging these even for failed requests
- Also logging `request_handled_by_load_shedder` for failed requests
- To accomplish that. `HTTPURLResponse` now conforms to our
`HTTPResponseType`, this allows us to extract headers in an uniform way
### Example:
```
[network] DEBUG: ℹ️ API request completed: GET '/v1/subscribers/$RCAnonymousID%3Ad9dc4f3b33054cf28c0f2ec9da0f48d5' (304)
Request-ID: 'be534c50-5231-403b-be2f-7c077861751d'; Amzn-Trace-ID: 'Root=1-6532c6ca-7ef80f961ec9c4145484df13'
```
This paves the way to add a second set of paths with a separate server
URL to be able to shed requests to offerings and product entitlement
mapping to a separate server.
### Changes:
- New `HTTPRequestPath` with the same properties as `HTTPRequest.Path` +
a new `serverHostURL`
- Moved proxy logic from `SystemInfo`/`HTTPClient` to `HTTPRequestPath`
- Simplified `HTTPRequest` implementation
### Changes:
- `HTTPClient` has a new `X-Post-Params-Hash` request header
- Replaced `HTTPRequest.Method.post`'s `Encodable` value with a more
specific `HTTPRequestBody` (like `HTTPResponseBody`)
- `HTTPRequestBody` allows overriding `contentForSignature` (it defaults
to `[]`) which then `Signing` uses for the hash
- Fixed `LogInOperation` not passing the `VerificationResult` to the
result `CustomerInfo`. This is captured in unit and integration tests
now.
- Add support for signing `POST` requests in `Path.logIn` and
`Path.postReceiptData`
Depends on https://github.com/RevenueCat/khepri/pull/6246
Example (the first `warn` log is `debug` and when running RC tests
only):
```
[signing] WARN: ⚠️ INVALID SIGNATURE DETECTED:
Request: GET /v1/subscribers/identify
Response: 200
Headers: ["X-Signature: signature", "X-RevenueCat-Request-Time: 1658749988564", "Content-Length: 0", "X-RevenueCat-ETag: etag"]
Body (length: 0): e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
[signing] ERROR: 😿‼️ Request to subscribers/identify failed verification. This is likely due to a malicious user intercepting and modifying requests.
```
Depends on #2747.
### Changes:
- Changed `Signing` to a `final class`, so it can be instantiated with
the api key.
- Updated all `SigningTests` to include the correct signatures
### Changes:
- `ETagManager` no longer stores the verification mode
- Created new `VerifiedHTTPResponse`, which has the
`VerificationResult`, extracted from `HTTPResponse`
- Removed `VerificationResult.from(cache:response:)`
- Changed `SignatureVerificationHTTPClientTests` to test using the real
`ETagManager`, so they become more "end to end" unit tests. A lot of
them were relying on implementation details of the mock instead of the
real `ETagManager`.
- Removed several `HTTPClient` tests that were checking a behavior that
was impossible (for example, no verification result despite it being
enabled), or that checked behavior based on the cached
`VerificationResult`
### New format:
- 32 bytes: intermediate public key
- 4 bytes: Expiration (in days since epoch)
- 64 bytes: intermediate public key signature, signed with the root
private key
- 16 bytes: salt
- 64 bytes: payload signature:
- salt
- nonce (if present)
- request time (as int string)
- etag (if present)
- payload
This also adds support for optional nonces for "static" signatures,
which is required for #2667.
Similar to #2486. This will be used for SDK-3181.
```
- WARN: ⚠️ Returning fake signature verification failure for 'GET /v1/subscribers/$RCAnonymousID:fc0508bea4a74a41bfc9a69db30d925f'
- ERROR: 😿‼️ Request failed signature verification. Request to /v1/subscribers/$RCAnonymousID%3Afc0508bea4a74a41bfc9a69db30d925f failed verification
```
Scenario:
- Response 1: 200 / `VerificationResult.failed`
- Response 2: 304 / `VerificationResult.verified`
Before this change, that was resulting in `VerificationResult.verified`,
even though it was using the unverified response body.
This fixes that so that we don't use the ETag for a response that failed
validation, even in `ResponseVerificationMode.informational`.