Skip to content

Commit 50b2080

Browse files
committed
fix: feedbacks
1 parent 705b1ef commit 50b2080

File tree

8 files changed

+103
-32
lines changed

8 files changed

+103
-32
lines changed

spec/ParseQuery.spec.js

Lines changed: 67 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5385,39 +5385,86 @@ describe('Parse.Query testing', () => {
53855385
});
53865386
});
53875387

5388-
it_id('DEPPS12')(it_only_db('mongo'))(
5389-
'throws error when using explain without master key',
5388+
it_id('a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d')(it_only_db('mongo'))(
5389+
'explain works with and without master key when allowPublicExplain is true',
53905390
async () => {
5391+
await reconfigureServer({
5392+
databaseURI: 'mongodb://localhost:27017/parse',
5393+
databaseAdapter: null,
5394+
databaseOptions: {
5395+
allowPublicExplain: true,
5396+
},
5397+
});
5398+
53915399
const obj = new TestObject({ foo: 'bar' });
53925400
await obj.save();
53935401

5394-
const spyLogRuntimeDeprecation = spyOn(Deprecator, 'logRuntimeDeprecation');
5395-
5396-
// Test that explain without master key throws an error
5402+
// Without master key
53975403
const query = new Parse.Query(TestObject);
53985404
query.explain();
5405+
const resultWithoutMasterKey = await query.find();
5406+
expect(resultWithoutMasterKey).toBeDefined();
53995407

5400-
try {
5401-
await query.find();
5408+
// With master key
5409+
const queryWithMasterKey = new Parse.Query(TestObject);
5410+
queryWithMasterKey.explain();
5411+
const resultWithMasterKey = await queryWithMasterKey.find({ useMasterKey: true });
5412+
expect(resultWithMasterKey).toBeDefined();
5413+
}
5414+
);
54025415

5403-
expect(spyLogRuntimeDeprecation).toHaveBeenCalledTimes(1);
5404-
expect(spyLogRuntimeDeprecation).toHaveBeenCalledWith({
5405-
usage: 'Using the explain query parameter without the master key',
5406-
});
5407-
// fail('Should have thrown an error');
5408-
} catch (error) {
5409-
// Uncomment this after the Deprecation DEPPS12
5410-
// expect(error.code).toEqual(Parse.Error.INVALID_QUERY);
5411-
// expect(error.message).toEqual('Using the explain query parameter without the master key');
5412-
}
5416+
it_id('b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e')(it_only_db('mongo'))(
5417+
'explain requires master key when allowPublicExplain is false',
5418+
async () => {
5419+
console.log("just before test")
5420+
await reconfigureServer({
5421+
databaseURI: 'mongodb://localhost:27017/parse',
5422+
databaseAdapter: null,
5423+
databaseOptions: {
5424+
allowPublicExplain: false,
5425+
},
5426+
});
5427+
5428+
const obj = new TestObject({ foo: 'bar' });
5429+
await obj.save();
5430+
5431+
// Without master key
5432+
const query = new Parse.Query(TestObject);
5433+
query.explain();
5434+
await expectAsync(query.find()).toBeRejectedWith(
5435+
new Parse.Error(
5436+
Parse.Error.INVALID_QUERY,
5437+
'Using the explain query parameter requires the master key'
5438+
)
5439+
);
54135440

5414-
// Test that explain with master key works fine
5441+
// With master key
54155442
const queryWithMasterKey = new Parse.Query(TestObject);
54165443
queryWithMasterKey.explain();
54175444
const result = await queryWithMasterKey.find({ useMasterKey: true });
5418-
5419-
// Should return explain result (not throw error)
54205445
expect(result).toBeDefined();
54215446
}
54225447
);
5448+
5449+
it_id('c3d4e5f6-a7b8-4c9d-0e1f-2a3b4c5d6e7f')(it_only_db('mongo'))(
5450+
'explain works with and without master key by default (allowPublicExplain not set)',
5451+
async () => {
5452+
await reconfigureServer({});
5453+
5454+
const obj = new TestObject({ foo: 'bar' });
5455+
await obj.save();
5456+
5457+
// Without master key (default behavior)
5458+
const query = new Parse.Query(TestObject);
5459+
query.explain();
5460+
const resultWithoutMasterKey = await query.find();
5461+
expect(resultWithoutMasterKey).toBeDefined();
5462+
5463+
// With master key
5464+
const queryWithMasterKey = new Parse.Query(TestObject);
5465+
queryWithMasterKey.explain();
5466+
const resultWithMasterKey = await queryWithMasterKey.find({ useMasterKey: true });
5467+
expect(resultWithMasterKey).toBeDefined();
5468+
}
5469+
);
54235470
});

src/Adapters/Storage/Mongo/MongoStorageAdapter.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,13 @@ export class MongoStorageAdapter implements StorageAdapter {
154154
this.enableSchemaHooks = !!mongoOptions.enableSchemaHooks;
155155
this.schemaCacheTtl = mongoOptions.schemaCacheTtl;
156156
this.disableIndexFieldValidation = !!mongoOptions.disableIndexFieldValidation;
157-
for (const key of ['enableSchemaHooks', 'schemaCacheTtl', 'maxTimeMS', 'disableIndexFieldValidation']) {
158-
delete mongoOptions[key];
157+
for (const key of [
158+
'enableSchemaHooks',
159+
'schemaCacheTtl',
160+
'maxTimeMS',
161+
'disableIndexFieldValidation',
162+
'allowPublicExplain',
163+
]) {
159164
delete this._mongoOptions[key];
160165
}
161166
}

src/Config.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,11 @@ export class Config {
602602
} else if (typeof databaseOptions.schemaCacheTtl !== 'number') {
603603
throw `databaseOptions.schemaCacheTtl must be a number`;
604604
}
605+
if (databaseOptions.allowPublicExplain === undefined) {
606+
databaseOptions.allowPublicExplain = DatabaseOptions.allowPublicExplain.default;
607+
} else if (typeof databaseOptions.allowPublicExplain !== 'boolean') {
608+
throw `databaseOptions.allowPublicExplain must be a boolean`;
609+
}
605610
}
606611

607612
static validateRateLimit(rateLimit) {

src/Deprecator/Deprecations.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,10 @@
1818
module.exports = [
1919
{ optionKey: 'encodeParseObjectInCloudFunction', changeNewDefault: 'true' },
2020
{ optionKey: 'enableInsecureAuthAdapters', changeNewDefault: 'false' },
21+
{
22+
optionKey: 'databaseOptions.allowPublicExplain',
23+
changeNewDefault: 'false',
24+
solution:
25+
'To prepare for the future change, set Parse Server option databaseOptions.allowPublicExplain to false and ensure explain queries are only made with master key.',
26+
},
2127
];

src/Options/Definitions.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,6 +1083,13 @@ module.exports.FileUploadOptions = {
10831083
},
10841084
};
10851085
module.exports.DatabaseOptions = {
1086+
allowPublicExplain: {
1087+
env: 'PARSE_SERVER_DATABASE_ALLOW_PUBLIC_EXPLAIN',
1088+
help:
1089+
'Set to `true` to allow explain queries without master key. This option is deprecated and the default will change to `false` in a future version.',
1090+
action: parsers.booleanParser,
1091+
default: true,
1092+
},
10861093
autoSelectFamily: {
10871094
env: 'PARSE_SERVER_DATABASE_AUTO_SELECT_FAMILY',
10881095
help:

src/Options/docs.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Options/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,9 @@ export interface DatabaseOptions {
634634
autoSelectFamilyAttemptTimeout: ?number;
635635
/* Set to `true` to disable validation of index fields. When disabled, indexes can be created even if the fields do not exist in the schema. This can be useful when creating indexes on fields that will be added later. */
636636
disableIndexFieldValidation: ?boolean;
637+
/* Set to `true` to allow explain queries without master key. This option is deprecated and the default will change to `false` in a future version.
638+
:DEFAULT: true */
639+
allowPublicExplain: ?boolean;
637640
}
638641

639642
export interface AuthAdapter {

src/rest.js

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ var RestQuery = require('./RestQuery');
1313
var RestWrite = require('./RestWrite');
1414
var triggers = require('./triggers');
1515
const { enforceRoleSecurity } = require('./SharedRest');
16-
const Deprecator = require('./Deprecator/Deprecator');
1716

1817
function checkTriggers(className, config, types) {
1918
return types.some(triggerType => {
@@ -37,16 +36,14 @@ async function runFindTriggers(
3736
const { isGet } = options;
3837

3938
if (restOptions && restOptions.explain && !auth.isMaster) {
40-
// After the Deprecation DEPPS12 uncomment this to throw an error
41-
// throw new Parse.Error(
42-
// Parse.Error.INVALID_QUERY,
43-
// 'Using the explain query parameter without the master key'
44-
// );
39+
const allowPublicExplain = config.databaseOptions?.allowPublicExplain ?? true;
4540

46-
// Deprecation DEPPS12
47-
Deprecator.logRuntimeDeprecation({
48-
usage: 'Using the explain query parameter without the master key',
49-
});
41+
if (!allowPublicExplain) {
42+
throw new Parse.Error(
43+
Parse.Error.INVALID_QUERY,
44+
'Using the explain query parameter requires the master key'
45+
);
46+
}
5047
}
5148

5249
// Run beforeFind trigger - may modify query or return objects directly

0 commit comments

Comments
 (0)