Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions spec/Deprecator.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,29 @@ describe('Deprecator', () => {
}
});

it('logs deprecation for enableProductPurchaseLegacyApi when set', async () => {
const logSpy = spyOn(Deprecator, '_logOption').and.callFake(() => {});

await reconfigureServer({ enableProductPurchaseLegacyApi: true });
expect(logSpy).toHaveBeenCalledWith(
jasmine.objectContaining({
optionKey: 'enableProductPurchaseLegacyApi',
changeNewKey: '',
})
);
});

it('does not log deprecation for enableProductPurchaseLegacyApi when not set', async () => {
const logSpy = spyOn(Deprecator, '_logOption').and.callFake(() => {});

await reconfigureServer();
expect(logSpy).not.toHaveBeenCalledWith(
jasmine.objectContaining({
optionKey: 'enableProductPurchaseLegacyApi',
})
);
});

it('does not log deprecation for requestComplexity limits when explicitly set', async () => {
const logSpy = spyOn(Deprecator, '_logOption').and.callFake(() => {});

Expand Down
25 changes: 25 additions & 0 deletions spec/PurchaseValidation.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,31 @@ describe('test validate_receipt endpoint', () => {
});
});

it('should disable validate_purchase endpoint when enableProductPurchaseLegacyApi is false', async () => {
await reconfigureServer({ enableProductPurchaseLegacyApi: false });
const ParseServer = require('../lib/ParseServer').default;
const routers = ParseServer.promiseRouter({
appId: 'test',
options: { enableProductPurchaseLegacyApi: false },
});
const hasValidatePurchase = routers.routes.some(
r => r.path === '/validate_purchase' && r.method === 'POST'
);
expect(hasValidatePurchase).toBe(false);
});

it('should enable validate_purchase endpoint by default', async () => {
const ParseServer = require('../lib/ParseServer').default;
const routers = ParseServer.promiseRouter({
appId: 'test',
options: {},
});
const hasValidatePurchase = routers.routes.some(
r => r.path === '/validate_purchase' && r.method === 'POST'
);
expect(hasValidatePurchase).toBe(true);
});

it('should not be able to remove a require key in a _Product', done => {
const query = new Parse.Query('_Product');
query
Expand Down
5 changes: 5 additions & 0 deletions src/Deprecator/Deprecations.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,9 @@ module.exports = [
changeNewDefault: '200',
solution: "Set 'requestComplexity.graphQLFields' to a positive integer appropriate for your app to limit the number of GraphQL field selections, or to '-1' to disable.",
},
{
optionKey: 'enableProductPurchaseLegacyApi',
changeNewKey: '',
solution: "The product purchase API is an undocumented, unmaintained legacy feature that may not function as expected and will be removed in a future major version. We strongly advise against using it. Set 'enableProductPurchaseLegacyApi' to 'false' to disable it, or remove the option to accept the future removal.",
},
];
6 changes: 6 additions & 0 deletions src/Options/Definitions.js
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,12 @@ module.exports.ParseServerOptions = {
action: parsers.booleanParser,
default: false,
},
enableProductPurchaseLegacyApi: {
env: 'PARSE_SERVER_ENABLE_PRODUCT_PURCHASE_LEGACY_API',
help: 'Deprecated. Enables the legacy product purchase API including the `_Product` class and the `/validate_purchase` endpoint. This is an undocumented, unmaintained legacy feature inherited from the original Parse platform that may not function as expected. We strongly advise against using it. It will be removed in a future major version.',
action: parsers.booleanParser,
default: true,
},
enableSanitizedErrorResponse: {
env: 'PARSE_SERVER_ENABLE_SANITIZED_ERROR_RESPONSE',
help: 'If set to `true`, error details are removed from error messages in responses to client requests, and instead a generic error message is sent. Default is `true`.',
Expand Down
1 change: 1 addition & 0 deletions src/Options/docs.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions src/Options/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,10 @@ export interface ParseServerOptions {
/* Enables the default express error handler for all errors
:DEFAULT: false */
enableExpressErrorHandler: ?boolean;
/* Deprecated. Enables the legacy product purchase API including the `_Product` class and the `/validate_purchase` endpoint. This is an undocumented, unmaintained legacy feature inherited from the original Parse platform that may not function as expected. We strongly advise against using it. It will be removed in a future major version.
:ENV: PARSE_SERVER_ENABLE_PRODUCT_PURCHASE_LEGACY_API
:DEFAULT: true */
enableProductPurchaseLegacyApi: ?boolean;
/* Sets the number of characters in generated object id's, default 10
:DEFAULT: 10 */
objectIdSize: ?number;
Expand Down
9 changes: 6 additions & 3 deletions src/ParseServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ class ParseServer {
}
api.use(middlewares.handleParseSession);
this.applyRequestContextMiddleware(api, options);
const appRouter = ParseServer.promiseRouter({ appId });
const appRouter = ParseServer.promiseRouter({ appId, options });
api.use(appRouter.expressRouter());

api.use(middlewares.handleParseErrors);
Expand Down Expand Up @@ -378,7 +378,7 @@ class ParseServer {
return api;
}

static promiseRouter({ appId }) {
static promiseRouter({ appId, options }) {
const routers = [
new ClassesRouter(),
new UsersRouter(),
Expand All @@ -390,7 +390,6 @@ class ParseServer {
new SchemasRouter(),
new PushRouter(),
new LogsRouter(),
new IAPValidationRouter(),
new FeaturesRouter(),
new GlobalConfigRouter(),
new GraphQLRouter(),
Expand All @@ -402,6 +401,10 @@ class ParseServer {
new SecurityRouter(),
];

if (options?.enableProductPurchaseLegacyApi !== false) {
routers.push(new IAPValidationRouter());
}

const routes = routers.reduce((memo, router) => {
return memo.concat(router.routes);
}, []);
Expand Down
Loading