refactor: Parse Pointer allows to access internal Parse Server classes and circumvent beforeFind query trigger (#8735)
This commit is contained in:
@@ -2431,6 +2431,35 @@ describe('beforeFind hooks', () => {
|
||||
})
|
||||
.then(() => done());
|
||||
});
|
||||
|
||||
it('should run beforeFind on pointers and array of pointers from an object', async () => {
|
||||
const obj1 = new Parse.Object('TestObject');
|
||||
const obj2 = new Parse.Object('TestObject2');
|
||||
const obj3 = new Parse.Object('TestObject');
|
||||
obj2.set('aField', 'aFieldValue');
|
||||
await obj2.save();
|
||||
obj1.set('pointerField', obj2);
|
||||
obj3.set('pointerFieldArray', [obj2]);
|
||||
await obj1.save();
|
||||
await obj3.save();
|
||||
const spy = jasmine.createSpy('beforeFindSpy');
|
||||
Parse.Cloud.beforeFind('TestObject2', spy);
|
||||
const query = new Parse.Query('TestObject');
|
||||
await query.get(obj1.id);
|
||||
// Pointer not included in query so we don't expect beforeFind to be called
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
const query2 = new Parse.Query('TestObject');
|
||||
query2.include('pointerField');
|
||||
const res = await query2.get(obj1.id);
|
||||
expect(res.get('pointerField').get('aField')).toBe('aFieldValue');
|
||||
// Pointer included in query so we expect beforeFind to be called
|
||||
expect(spy).toHaveBeenCalledTimes(1);
|
||||
const query3 = new Parse.Query('TestObject');
|
||||
query3.include('pointerFieldArray');
|
||||
const res2 = await query3.get(obj3.id);
|
||||
expect(res2.get('pointerFieldArray')[0].get('aField')).toBe('aFieldValue');
|
||||
expect(spy).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('afterFind hooks', () => {
|
||||
|
||||
@@ -5275,7 +5275,6 @@ describe('ParseGraphQLServer', () => {
|
||||
|
||||
it('should only count', async () => {
|
||||
await prepareData();
|
||||
|
||||
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
|
||||
|
||||
const where = {
|
||||
|
||||
@@ -142,7 +142,7 @@ describe('Parse Role testing', () => {
|
||||
return Promise.all(promises);
|
||||
};
|
||||
|
||||
const restExecute = spyOn(RestQuery.prototype, 'execute').and.callThrough();
|
||||
const restExecute = spyOn(RestQuery._UnsafeRestQuery.prototype, 'execute').and.callThrough();
|
||||
|
||||
let user, auth, getAllRolesSpy;
|
||||
createTestUser()
|
||||
|
||||
@@ -399,15 +399,16 @@ describe('RestQuery.each', () => {
|
||||
}
|
||||
const config = Config.get('test');
|
||||
await Parse.Object.saveAll(objects);
|
||||
const query = new RestQuery(
|
||||
const query = await RestQuery({
|
||||
method: RestQuery.Method.find,
|
||||
config,
|
||||
auth.master(config),
|
||||
'Object',
|
||||
{ value: { $gt: 2 } },
|
||||
{ limit: 2 }
|
||||
);
|
||||
auth: auth.master(config),
|
||||
className: 'Object',
|
||||
restWhere: { value: { $gt: 2 } },
|
||||
restOptions: { limit: 2 },
|
||||
});
|
||||
const spy = spyOn(query, 'execute').and.callThrough();
|
||||
const classSpy = spyOn(RestQuery.prototype, 'execute').and.callThrough();
|
||||
const classSpy = spyOn(RestQuery._UnsafeRestQuery.prototype, 'execute').and.callThrough();
|
||||
const results = [];
|
||||
await query.each(result => {
|
||||
expect(result.value).toBeGreaterThan(2);
|
||||
@@ -438,34 +439,37 @@ describe('RestQuery.each', () => {
|
||||
* Two queries needed since objectId are sorted and we can't know which one
|
||||
* going to be the first and then skip by the $gt added by each
|
||||
*/
|
||||
const queryOne = new RestQuery(
|
||||
const queryOne = await RestQuery({
|
||||
method: RestQuery.Method.get,
|
||||
config,
|
||||
auth.master(config),
|
||||
'Letter',
|
||||
{
|
||||
auth: auth.master(config),
|
||||
className: 'Letter',
|
||||
restWhere: {
|
||||
numbers: {
|
||||
__type: 'Pointer',
|
||||
className: 'Number',
|
||||
objectId: object1.id,
|
||||
},
|
||||
},
|
||||
{ limit: 1 }
|
||||
);
|
||||
const queryTwo = new RestQuery(
|
||||
restOptions: { limit: 1 },
|
||||
});
|
||||
|
||||
const queryTwo = await RestQuery({
|
||||
method: RestQuery.Method.get,
|
||||
config,
|
||||
auth.master(config),
|
||||
'Letter',
|
||||
{
|
||||
auth: auth.master(config),
|
||||
className: 'Letter',
|
||||
restWhere: {
|
||||
numbers: {
|
||||
__type: 'Pointer',
|
||||
className: 'Number',
|
||||
objectId: object2.id,
|
||||
},
|
||||
},
|
||||
{ limit: 1 }
|
||||
);
|
||||
restOptions: { limit: 1 },
|
||||
});
|
||||
|
||||
const classSpy = spyOn(RestQuery.prototype, 'execute').and.callThrough();
|
||||
const classSpy = spyOn(RestQuery._UnsafeRestQuery.prototype, 'execute').and.callThrough();
|
||||
const resultsOne = [];
|
||||
const resultsTwo = [];
|
||||
await queryOne.each(result => {
|
||||
|
||||
@@ -660,6 +660,38 @@ describe('rest create', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('cannot get object in volatileClasses if not masterKey through pointer', async () => {
|
||||
const masterKeyOnlyClassObject = new Parse.Object('_PushStatus');
|
||||
await masterKeyOnlyClassObject.save(null, { useMasterKey: true });
|
||||
const obj2 = new Parse.Object('TestObject');
|
||||
// Anyone is can basically create a pointer to any object
|
||||
// or some developers can use master key in some hook to link
|
||||
// private objects to standard objects
|
||||
obj2.set('pointer', masterKeyOnlyClassObject);
|
||||
await obj2.save();
|
||||
const query = new Parse.Query('TestObject');
|
||||
query.include('pointer');
|
||||
await expectAsync(query.get(obj2.id)).toBeRejectedWithError(
|
||||
"Clients aren't allowed to perform the get operation on the _PushStatus collection."
|
||||
);
|
||||
});
|
||||
|
||||
it('cannot get object in _GlobalConfig if not masterKey through pointer', async () => {
|
||||
await Parse.Config.save({ privateData: 'secret' }, { privateData: true });
|
||||
const obj2 = new Parse.Object('TestObject');
|
||||
obj2.set('globalConfigPointer', {
|
||||
__type: 'Pointer',
|
||||
className: '_GlobalConfig',
|
||||
objectId: 1,
|
||||
});
|
||||
await obj2.save();
|
||||
const query = new Parse.Query('TestObject');
|
||||
query.include('globalConfigPointer');
|
||||
await expectAsync(query.get(obj2.id)).toBeRejectedWithError(
|
||||
"Clients aren't allowed to perform the get operation on the _GlobalConfig collection."
|
||||
);
|
||||
});
|
||||
|
||||
it('locks down session', done => {
|
||||
let currentUser;
|
||||
Parse.User.signUp('foo', 'bar')
|
||||
|
||||
Reference in New Issue
Block a user