apple / apple/app-store-server-library-node

Subscription status response validators omit validation of data and nested lastTransactions

Open
#450 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
382
Forks
79
Avg merge
1d 7h
Merged PRs (30d)
9

Description

### Description

`StatusResponseValidator` checks `environment`, `bundleId` and `appAppleId`, but never validates `data`, which is declared as `SubscriptionGroupIdentifierItem[]`.

There is a second gap in the nested model: `SubscriptionGroupIdentifierItemValidator` checks only `subscriptionGroupIdentifier` and never validates `lastTransactions`, which is declared as `LastTransactionsItem[]`.

Consequently, the response validator accepts a non-array `data` value, malformed subscription-group entries and malformed transaction entries. Connecting `StatusResponseValidator` to the existing subscription-group validator alone would not fully address the problem, because that validator also omits its nested array.

### Reproduction

From the repository root, after building the package:

```js
const {
StatusResponseValidator,
} = require('./dist/models/StatusResponse.js');
const {
SubscriptionGroupIdentifierItemValidator,
} = require('./dist/models/SubscriptionGroupIdentifierItem.js');
const {
LastTransactionsItemValidator,
} = require('./dist/models/LastTransactionsItem.js');

const responseValidator = new StatusResponseValidator();
const groupValidator = new SubscriptionGroupIdentifierItemValidator();
const transactionValidator = new LastTransactionsItemValidator();

console.log(responseValidator.validate({ data: 'not-an-array' }));
// true

console.log(groupValidator.validate({ lastTransactions: 'not-an-array' }));
// true

const invalidTransaction = { signedTransactionInfo: 123 };
console.log(responseValidator.validate({
data: [{
subscriptionGroupIdentifier: '123',
lastTransactions: [invalidTransaction],
}],
}));
// true

console.log(transactionValidator.validate(invalidTransaction));
// false
```

### Expected behavior

When present, `data` must be an array of valid subscription-group items. Within each group, `lastTransactions`, when present, must be an array of valid transaction items. Invalid nested values should cause validation of the containing response to return false.

Omitted optional fields should remain accepted, consistent with the current model definitions.

### Impact

`AppStoreServerAPIClient.getAllSubscriptionStatuses` uses `StatusResponseValidator`. Its runtime validation therefore does not enforce the declared structure of the subscription data returned to callers. Downstream code may receive incompatible values despite a successful client validation result.

This concerns structural validation of the API response. Cryptographic verification of the signed transaction and renewal payloads remains a separate operation.

### Suggested change

- In `StatusResponseValidator`, check that a present `data` value is an array and validate each entry with `SubscriptionGroupIdentifierItemValidator`.
- In `SubscriptionGroupIdentifierItemValidator`, check that a present `lastTransactions` value is an array and validate each entry with `LastTransactionsItemValidator`.
- Add regression coverage for invalid array types, invalid nested fields and valid nested responses.

Contributor guide

Open the contributing guide

Research direction

Start by inspecting the validators in dist/models/StatusResponse.js, dist/models/SubscriptionGroupIdentifierItem.js, and dist/models/LastTransactionsItem.js after building the package. Trace how optional arrays and nested validators are handled, then add regression coverage for invalid array types, malformed nested entries, and valid omitted or nested fields. Done means invalid nested responses return false while valid responses and omitted optional fields remain accepted.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
84/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.