import { noContentError, notFoundError } from "./network"; /** * Validate an untrusted adam ID without contacting the server. * * This allows avoiding the work of calling the server with completely bogus * IDs. It's scoped to web since ID formats can change and web can be updated * easily (whereas backporting to older native clients is trickier). * * @param {AppStoreObjectGraph} objectGraph * @param {string} id - the Adam ID to validate * @returns {void} undefined if valid, throws a `NetworkError` (204) otherwise */ export function validateAdamId(objectGraph, id) { if (objectGraph.client.isWeb && !isAdamId(id)) { throw noContentError(); } } /** * Check if an ID is a valid Adam ID. * * @param {string} id - string to validate * @return {boolean} true if valid, false otherwise */ function isAdamId(id) { // Media API actually validates if the number <= 2^63-1. But doubles in // JavaScript cannot precisely represent this (the closest number is >2^63) // so checking this requires BigInt, which might not be available. At the // end of the day, checking this is likely not worth the complexity. 2^63-1 // is 9223372036854775807 so we just restrict the number of digits. // // See: https://github.pie.apple.com/its/amp-enums/blob/f75500b44f871f35ba3ce459a5ff4c9f225e71b0/src/main/java/com/apple/jingle/store/IdSpace.java#L131-L140 // See: https://github.com/google/guava/blob/869a75a1e3ff85d36672a3cd154772dc90c7b3d2/guava/src/com/google/common/primitives/Longs.java#L400-L440 // See: https://docs.oracle.com/en/java/javase/24/docs/api/java.base/java/lang/Long.html#MAX_VALUE return /^\d{1,19}$/.test(id); } /** * Validate an untrusted Featured Content ID without contacting the server. * * This allows avoiding the work of calling the server with completely bogus * IDs. It's scoped to web since ID formats can change and web can be updated * easily (whereas backporting to older native clients is trickier). * * @param {AppStoreObjectGraph} objectGraph * @param {string} id the FC ID to validate * @returns {void} undefined if valid, throws a `NetworkError` (204) otherwise */ export function validateFcId(objectGraph, id) { if (objectGraph.client.isWeb && !isFcId(id)) { throw noContentError(); } } /** * Check if an ID is a valid Featured Content (FC) ID. * * @param {string} id - string to validate * @return {boolean} true if valid, false otherwise */ function isFcId(id) { // FcIds are actually Adam IDs under the hood. // See: https://github.pie.apple.com/its/Jingle/blob/d2d051c9ef2891f72d5f02f5bbbf2d7748afa7b9/MZStoreComponents/src/main/java/com/apple/jingle/app/store/editorial/SFEditorialHelper.java#L293 return isAdamId(id); } /** * Validate an untrusted (Chart) Genre ID without contacting the server. * * This allows avoiding the work of calling the server with completely bogus * IDs. It's scoped to web since ID formats can change and web can be updated * easily (whereas backporting to older native clients is trickier). * * @param {AppStoreObjectGraph} objectGraph * @param {string} id the genre ID to validate * @returns {void} undefined if valid, throws a `NetworkError` (204) otherwise */ export function validateGenreId(objectGraph, id) { if (objectGraph.client.isWeb && !isGenreId(id)) { throw noContentError(); } } /** * Check if an ID is a valid (Chart) Genre ID. * * @param {string} id - string to validate * @return {boolean} true if valid, false otherwise */ function isGenreId(id) { // Genre IDs are Java int (signed 32-bit). // // Technically negative is not excluded, but all charts are positive, so // filter out negative. // // See: https://github.pie.apple.com/its/Jingle/blob/main/shared/reference-data-logic/MZReferenceDataLogic/src/main/java/com/apple/jingle/eo/MZGenreService.java#L555 return isPositiveJavaInt(id); } /** * Validate an untrusted Grouping ID without contacting the server. * * This allows avoiding the work of calling the server with completely bogus * IDs. It's scoped to web since ID formats can change and web can be updated * easily (whereas backporting to older native clients is trickier). * * @param {AppStoreObjectGraph} objectGraph * @param {string} id the grouping ID to validate * @returns {void} undefined if valid, throws a `NetworkError` (204) otherwise */ export function validateGroupingId(objectGraph, id) { if (objectGraph.client.isWeb && !isGroupingId(id)) { throw noContentError(); } } /** * Check if an ID is a valid Grouping ID. * * @param {string} id - string to validate * @return {boolean} true if valid, false otherwise */ function isGroupingId(id) { // Grouping IDs are Java int (signed 32-bit) // // Technically negative does not fail to parse, but they're all positive in // practice. // // See: https://github.pie.apple.com/its/Jingle/blob/aaccec936f1feed227fd171ae66bb160cf38e497/MZStorePlatform/src/main/java/com/apple/jingle/store/mediaapi/util/SFMediaAPIEditorialUtil.java#L634 return isPositiveJavaInt(id); } /** * Test if a string contains a Java int. * * @param {string} s - the string to test * @returns {boolean} true if the string is a stringified Java int, false otherwise */ function isPositiveJavaInt(s) { // Java int is 32-bit signed. We can check bounds since signed integers are // exactly representable as doubles (actually up to 2^53 is representable // exactly). // // See: https://docs.oracle.com/en/java/javase/24/docs/api/java.base/java/lang/Integer.html#MAX_VALUE return /^\d+$/.test(s) && parseInt(s, 10) <= 2147483647; } /** * Validate an untrusted Editorial Shelf Collection ID without contacting the server. * * This allows avoiding the work of calling the server with completely bogus * IDs. It's scoped to web since ID formats can change and web can be updated * easily (whereas backporting to older native clients is trickier). * * @param {AppStoreObjectGraph} objectGraph * @param {string} id the editorial shelf collection ID to validate * @returns {void} undefined if valid, throws a `NetworkError` (204) otherwise */ export function validateEditorialShelfCollectionId(objectGraph, id) { if (objectGraph.client.isWeb && !isEditorialShelfCollectionId(id)) { throw noContentError(); } } /** * Check if an ID is a valid editorial shelf collection ID. * * @param {string} id - string to validate * @return {boolean} true if valid, false otherwise */ function isEditorialShelfCollectionId(id) { // Ids are prefixed with "eds.". Beyond that they do have a UUID-type // identifier that follows, but that seems more liable to change. // // See: https://github.pie.apple.com/its/amp-enums/blob/f75500b44f871f35ba3ce459a5ff4c9f225e71b0/src/main/java/com/apple/jingle/store/IdSpace.java#L43C5-L43C20 // See: https://github.pie.apple.com/its/amp-enums/blob/f75500b44f871f35ba3ce459a5ff4c9f225e71b0/src/main/java/com/apple/jingle/store/IdSpace.java#L250-L252 return id.startsWith("eds."); } /** * Validates if a request can be performed for `vision` platform content, based on * the feature flag is disabled. * * @param {AppStoreObjectGraph} objectGraph The application's state graph. * @throws {NetworkError} Throws a 404 error if access is restricted. * @returns {void} */ export function validateNeedsVisionRestriction(objectGraph) { var _a; if (objectGraph.client.isWeb && ((_a = objectGraph.activeIntent) === null || _a === void 0 ? void 0 : _a.previewPlatform) === "vision" && !objectGraph.bag.enableVisionPlatform) { throw notFoundError(); } } //# sourceMappingURL=util.js.map