Skip to content

Commit 8584f36

Browse files
committed
fix
1 parent 6286d2e commit 8584f36

File tree

4 files changed

+127
-25
lines changed

4 files changed

+127
-25
lines changed

spec/ParseLiveQuery.spec.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,52 @@ describe('ParseLiveQuery', function () {
974974
}
975975
});
976976

977+
it('should strip out protected fields', async () => {
978+
await reconfigureServer({
979+
liveQuery: { classNames: ['Test'] },
980+
startLiveQueryServer: true,
981+
});
982+
const obj1 = new Parse.Object('Test');
983+
obj1.set('foo', 'foo');
984+
obj1.set('bar', 'bar');
985+
obj1.set('qux', 'qux');
986+
await obj1.save();
987+
const config = Config.get(Parse.applicationId);
988+
const schemaController = await config.database.loadSchema();
989+
await schemaController.updateClass(
990+
'Test',
991+
{},
992+
{
993+
get: { '*': true },
994+
find: { '*': true },
995+
update: { '*': true },
996+
protectedFields: {
997+
'*': ['foo'],
998+
},
999+
}
1000+
);
1001+
const object = await obj1.fetch();
1002+
expect(object.get('foo')).toBe(undefined);
1003+
expect(object.get('bar')).toBeDefined();
1004+
expect(object.get('qux')).toBeDefined();
1005+
1006+
const subscription = await new Parse.Query('Test').subscribe();
1007+
await Promise.all([
1008+
new Promise(resolve => {
1009+
subscription.on('update', (obj, original) => {
1010+
expect(obj.get('foo')).toBe(undefined);
1011+
expect(obj.get('bar')).toBeDefined();
1012+
expect(obj.get('qux')).toBeDefined();
1013+
expect(original.get('foo')).toBe(undefined);
1014+
expect(original.get('bar')).toBeDefined();
1015+
expect(original.get('qux')).toBeDefined();
1016+
resolve();
1017+
});
1018+
}),
1019+
obj1.save({ foo: 'abc' }),
1020+
]);
1021+
});
1022+
9771023
afterEach(async function (done) {
9781024
const client = await Parse.CoreManager.getLiveQueryController().getDefaultLiveQueryClient();
9791025
client.close();

src/Controllers/DatabaseController.js

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,16 +123,28 @@ const filterSensitiveData = (
123123
aclGroup: any[],
124124
auth: any,
125125
operation: any,
126-
schema: SchemaController.SchemaController,
126+
schema: SchemaController.SchemaController | any,
127127
className: string,
128128
protectedFields: null | Array<any>,
129-
object: any
129+
object: any,
130+
query: any = {}
130131
) => {
132+
if (!isMaster && !Array.isArray(protectedFields)) {
133+
protectedFields = new DatabaseController().addProtectedFields(
134+
schema,
135+
className,
136+
query,
137+
aclGroup,
138+
auth
139+
);
140+
}
141+
131142
let userId = null;
132143
if (auth && auth.user) userId = auth.user.id;
133144

134145
// replace protectedFields when using pointer-permissions
135-
const perms = schema.getClassLevelPermissions(className);
146+
const perms =
147+
schema && schema.getClassLevelPermissions ? schema.getClassLevelPermissions(className) : {};
136148
if (perms) {
137149
const isReadOperation = ['get', 'find'].indexOf(operation) > -1;
138150

@@ -1430,14 +1442,17 @@ class DatabaseController {
14301442
}
14311443

14321444
addProtectedFields(
1433-
schema: SchemaController.SchemaController,
1445+
schema: SchemaController.SchemaController | any,
14341446
className: string,
14351447
query: any = {},
14361448
aclGroup: any[] = [],
14371449
auth: any = {},
14381450
queryOptions: FullQueryOptions = {}
14391451
): null | string[] {
1440-
const perms = schema.getClassLevelPermissions(className);
1452+
const perms =
1453+
schema && schema.getClassLevelPermissions
1454+
? schema.getClassLevelPermissions(className)
1455+
: schema;
14411456
if (!perms) return null;
14421457

14431458
const protectedFields = perms.protectedFields;
@@ -1746,3 +1761,4 @@ class DatabaseController {
17461761
module.exports = DatabaseController;
17471762
// Expose validateQuery for tests
17481763
module.exports._validateQuery = validateQuery;
1764+
module.exports.filterSensitiveData = filterSensitiveData;

src/LiveQuery/ParseCloudCodePublisher.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ class ParseCloudCodePublisher {
3333
if (request.original) {
3434
message.originalParseObject = request.original._toFullJSON();
3535
}
36+
if (request.classLevelPermissions) {
37+
message.classLevelPermissions = request.classLevelPermissions;
38+
}
3639
this.parsePublisher.publish(type, JSON.stringify(message));
3740
}
3841
}

src/LiveQuery/ParseLiveQueryServer.js

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { getAuthForSessionToken, Auth } from '../Auth';
2020
import { getCacheController } from '../Controllers';
2121
import LRU from 'lru-cache';
2222
import UserRouter from '../Routers/UsersRouter';
23+
import DatabaseController from '../Controllers/DatabaseController';
2324

2425
class ParseLiveQueryServer {
2526
clients: Map;
@@ -171,22 +172,22 @@ class ParseLiveQueryServer {
171172
};
172173
return maybeRunAfterEventTrigger('afterEvent', className, res);
173174
})
174-
.then(() => {
175+
.then(async () => {
175176
if (!res.sendEvent) {
176177
return;
177178
}
178179
if (res.object && typeof res.object.toJSON === 'function') {
179180
deletedParseObject = res.object.toJSON();
180181
deletedParseObject.className = className;
181182
}
182-
if (
183-
(deletedParseObject.className === '_User' ||
184-
deletedParseObject.className === '_Session') &&
185-
!client.hasMasterKey
186-
) {
187-
delete deletedParseObject.sessionToken;
188-
delete deletedParseObject.authData;
189-
}
183+
await this._filterSensitiveData(
184+
classLevelPermissions,
185+
res,
186+
client,
187+
requestId,
188+
op,
189+
subscription.query
190+
);
190191
client.pushDelete(requestId, deletedParseObject);
191192
})
192193
.catch(error => {
@@ -310,7 +311,7 @@ class ParseLiveQueryServer {
310311
return maybeRunAfterEventTrigger('afterEvent', className, res);
311312
})
312313
.then(
313-
() => {
314+
async () => {
314315
if (!res.sendEvent) {
315316
return;
316317
}
@@ -323,16 +324,14 @@ class ParseLiveQueryServer {
323324
originalParseObject = res.original.toJSON();
324325
originalParseObject.className = res.original.className || className;
325326
}
326-
if (
327-
(currentParseObject.className === '_User' ||
328-
currentParseObject.className === '_Session') &&
329-
!client.hasMasterKey
330-
) {
331-
delete currentParseObject.sessionToken;
332-
delete originalParseObject?.sessionToken;
333-
delete currentParseObject.authData;
334-
delete originalParseObject?.authData;
335-
}
327+
await this._filterSensitiveData(
328+
classLevelPermissions,
329+
res,
330+
client,
331+
requestId,
332+
op,
333+
subscription.query
334+
);
336335
const functionName =
337336
'push' + message.event.charAt(0).toUpperCase() + message.event.slice(1);
338337
if (client[functionName]) {
@@ -532,6 +531,44 @@ class ParseLiveQueryServer {
532531
// return rolesQuery.find({useMasterKey:true});
533532
}
534533

534+
async _filterSensitiveData(
535+
classLevelPermissions: ?any,
536+
res: any,
537+
client: any,
538+
requestId: number,
539+
op: string,
540+
query: any
541+
) {
542+
const subscriptionInfo = client.getSubscriptionInfo(requestId);
543+
const aclGroup = ['*'];
544+
let clientAuth;
545+
if (typeof subscriptionInfo !== 'undefined') {
546+
const { userId, auth } = await this.getAuthForSessionToken(subscriptionInfo.sessionToken);
547+
if (userId) {
548+
aclGroup.push(userId);
549+
}
550+
clientAuth = auth;
551+
}
552+
const filter = obj => {
553+
if (!obj) {
554+
return;
555+
}
556+
return DatabaseController.filterSensitiveData(
557+
client.hasMasterKey,
558+
aclGroup,
559+
clientAuth,
560+
op,
561+
classLevelPermissions,
562+
res.object.className,
563+
classLevelPermissions?.protectedFields,
564+
obj,
565+
query
566+
);
567+
};
568+
res.object = filter(res.object);
569+
res.original = filter(res.original);
570+
}
571+
535572
_getCLPOperation(query: any) {
536573
return typeof query === 'object' &&
537574
Object.keys(query).length == 1 &&

0 commit comments

Comments
 (0)