Skip to content

Commit a60ad68

Browse files
committed
new: validate cloud validators
1 parent 25fb576 commit a60ad68

File tree

2 files changed

+140
-0
lines changed

2 files changed

+140
-0
lines changed

spec/CloudCode.Validator.spec.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,4 +1266,62 @@ describe('cloud validator', () => {
12661266
done();
12671267
}
12681268
});
1269+
1270+
it('Logs on invalid config', () => {
1271+
const logger = require('../lib/logger').logger;
1272+
spyOn(logger, 'error').and.callFake(() => {});
1273+
Parse.Cloud.define('myFunction', () => {}, {
1274+
requiredUser: true,
1275+
requireUser: ['foo'],
1276+
requireMaster: ['foo'],
1277+
validateMasterKey: ['foo'],
1278+
skipWithMasterKey: ['foo'],
1279+
requireUserKeys: true,
1280+
fields: true,
1281+
});
1282+
expect(logger.error).toHaveBeenCalledWith(
1283+
'requiredUser is not a supported paramter for Parse.Cloud validators.'
1284+
);
1285+
expect(logger.error).toHaveBeenCalledWith(
1286+
'Invalid type for Parse.Cloud validator key requireUser. Expected boolean, actual array'
1287+
);
1288+
expect(logger.error).toHaveBeenCalledWith(
1289+
'Invalid type for Parse.Cloud validator key requireMaster. Expected boolean, actual array'
1290+
);
1291+
expect(logger.error).toHaveBeenCalledWith(
1292+
'Invalid type for Parse.Cloud validator key validateMasterKey. Expected boolean, actual array'
1293+
);
1294+
expect(logger.error).toHaveBeenCalledWith(
1295+
'Invalid type for Parse.Cloud validator key skipWithMasterKey. Expected boolean, actual array'
1296+
);
1297+
expect(logger.error).toHaveBeenCalledWith(
1298+
'Invalid type for Parse.Cloud validator key fields. Expected array|object, actual boolean'
1299+
);
1300+
expect(logger.error).toHaveBeenCalledWith(
1301+
'Invalid type for Parse.Cloud validator key requireUserKeys. Expected array|object, actual boolean'
1302+
);
1303+
});
1304+
1305+
it('Logs on invalid config', () => {
1306+
const logger = require('../lib/logger').logger;
1307+
spyOn(logger, 'error').and.callFake(() => {});
1308+
Parse.Cloud.define('myFunction', () => {}, {
1309+
fields: {
1310+
name: {
1311+
constant: ['foo'],
1312+
required: ['foo'],
1313+
error: ['foo'],
1314+
},
1315+
},
1316+
});
1317+
expect(logger.error).toHaveBeenCalledWith(
1318+
'Invalid type for Parse.Cloud validator key constant. Expected boolean, actual array'
1319+
);
1320+
expect(logger.error).toHaveBeenCalledWith(
1321+
'Invalid type for Parse.Cloud validator key required. Expected boolean, actual array'
1322+
);
1323+
expect(logger.error).toHaveBeenCalledWith(
1324+
'Invalid type for Parse.Cloud validator key error. Expected string, actual array'
1325+
);
1326+
});
12691327
});

src/cloud-code/Parse.Cloud.js

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,74 @@ function getClassName(parseClass) {
1313
return parseClass;
1414
}
1515

16+
function validateValidator(validator) {
17+
if (!validator || typeof validator === 'function') {
18+
return;
19+
}
20+
const fieldOptions = {
21+
type: ['Any'],
22+
constant: [Boolean],
23+
default: ['Any'],
24+
options: [Array, 'function', 'Any'],
25+
required: [Boolean],
26+
error: [String],
27+
};
28+
const allowedKeys = {
29+
requireUser: [Boolean],
30+
requireMaster: [Boolean],
31+
validateMasterKey: [Boolean],
32+
skipWithMasterKey: [Boolean],
33+
requireUserKeys: [Array, Object],
34+
fields: [Array, Object],
35+
};
36+
const config = Config.get(Parse.applicationId);
37+
const logger = config.loggerController;
38+
const getType = fn => {
39+
if (Array.isArray(fn)) {
40+
return 'array';
41+
}
42+
if (fn === 'Any') {
43+
return fn;
44+
}
45+
const type = typeof fn;
46+
if (typeof fn === 'function') {
47+
const match = fn && fn.toString().match(/^\s*function (\w+)/);
48+
return (match ? match[1] : '').toLowerCase();
49+
}
50+
return type;
51+
};
52+
const checkKey = (key, data, validatorParam) => {
53+
const parameter = data[key];
54+
if (!parameter) {
55+
logger.error(`${key} is not a supported paramter for Parse.Cloud validators.`);
56+
return;
57+
}
58+
const types = parameter.map(type => getType(type));
59+
const type = getType(validatorParam);
60+
if (!types.includes(type) && !types.includes('Any')) {
61+
logger.error(
62+
`Invalid type for Parse.Cloud validator key ${key}. Expected ${types.join(
63+
'|'
64+
)}, actual ${type}`
65+
);
66+
}
67+
};
68+
for (const key in validator) {
69+
checkKey(key, allowedKeys, validator[key]);
70+
if (key === 'fields' || key === 'requireUserKeys') {
71+
const values = validator[key];
72+
if (Array.isArray(values)) {
73+
continue;
74+
}
75+
for (const value in values) {
76+
const data = values[value];
77+
for (const subKey in data) {
78+
checkKey(subKey, fieldOptions, data[subKey]);
79+
}
80+
}
81+
}
82+
}
83+
}
1684
/** @namespace
1785
* @name Parse
1886
* @description The Parse SDK.
@@ -50,6 +118,7 @@ var ParseCloud = {};
50118
* @param {(Object|Function)} validator An optional function to help validating cloud code. This function can be an async function and should take one parameter a {@link Parse.Cloud.FunctionRequest}, or a {@link Parse.Cloud.ValidatorObject}.
51119
*/
52120
ParseCloud.define = function (functionName, handler, validationHandler) {
121+
validateValidator(validationHandler);
53122
triggers.addFunction(functionName, handler, validationHandler, Parse.applicationId);
54123
};
55124

@@ -96,6 +165,7 @@ ParseCloud.job = function (functionName, handler) {
96165
*/
97166
ParseCloud.beforeSave = function (parseClass, handler, validationHandler) {
98167
var className = getClassName(parseClass);
168+
validateValidator(validationHandler);
99169
triggers.addTrigger(
100170
triggers.Types.beforeSave,
101171
className,
@@ -131,6 +201,7 @@ ParseCloud.beforeSave = function (parseClass, handler, validationHandler) {
131201
*/
132202
ParseCloud.beforeDelete = function (parseClass, handler, validationHandler) {
133203
var className = getClassName(parseClass);
204+
validateValidator(validationHandler);
134205
triggers.addTrigger(
135206
triggers.Types.beforeDelete,
136207
className,
@@ -260,6 +331,7 @@ ParseCloud.afterLogout = function (handler) {
260331
*/
261332
ParseCloud.afterSave = function (parseClass, handler, validationHandler) {
262333
var className = getClassName(parseClass);
334+
validateValidator(validationHandler);
263335
triggers.addTrigger(
264336
triggers.Types.afterSave,
265337
className,
@@ -295,6 +367,7 @@ ParseCloud.afterSave = function (parseClass, handler, validationHandler) {
295367
*/
296368
ParseCloud.afterDelete = function (parseClass, handler, validationHandler) {
297369
var className = getClassName(parseClass);
370+
validateValidator(validationHandler);
298371
triggers.addTrigger(
299372
triggers.Types.afterDelete,
300373
className,
@@ -330,6 +403,7 @@ ParseCloud.afterDelete = function (parseClass, handler, validationHandler) {
330403
*/
331404
ParseCloud.beforeFind = function (parseClass, handler, validationHandler) {
332405
var className = getClassName(parseClass);
406+
validateValidator(validationHandler);
333407
triggers.addTrigger(
334408
triggers.Types.beforeFind,
335409
className,
@@ -365,6 +439,7 @@ ParseCloud.beforeFind = function (parseClass, handler, validationHandler) {
365439
*/
366440
ParseCloud.afterFind = function (parseClass, handler, validationHandler) {
367441
const className = getClassName(parseClass);
442+
validateValidator(validationHandler);
368443
triggers.addTrigger(
369444
triggers.Types.afterFind,
370445
className,
@@ -397,6 +472,7 @@ ParseCloud.afterFind = function (parseClass, handler, validationHandler) {
397472
* @param {(Object|Function)} validator An optional function to help validating cloud code. This function can be an async function and should take one parameter a {@link Parse.Cloud.FileTriggerRequest}, or a {@link Parse.Cloud.ValidatorObject}.
398473
*/
399474
ParseCloud.beforeSaveFile = function (handler, validationHandler) {
475+
validateValidator(validationHandler);
400476
triggers.addFileTrigger(
401477
triggers.Types.beforeSaveFile,
402478
handler,
@@ -428,6 +504,7 @@ ParseCloud.beforeSaveFile = function (handler, validationHandler) {
428504
* @param {(Object|Function)} validator An optional function to help validating cloud code. This function can be an async function and should take one parameter a {@link Parse.Cloud.FileTriggerRequest}, or a {@link Parse.Cloud.ValidatorObject}.
429505
*/
430506
ParseCloud.afterSaveFile = function (handler, validationHandler) {
507+
validateValidator(validationHandler);
431508
triggers.addFileTrigger(
432509
triggers.Types.afterSaveFile,
433510
handler,
@@ -459,6 +536,7 @@ ParseCloud.afterSaveFile = function (handler, validationHandler) {
459536
* @param {(Object|Function)} validator An optional function to help validating cloud code. This function can be an async function and should take one parameter a {@link Parse.Cloud.FileTriggerRequest}, or a {@link Parse.Cloud.ValidatorObject}.
460537
*/
461538
ParseCloud.beforeDeleteFile = function (handler, validationHandler) {
539+
validateValidator(validationHandler);
462540
triggers.addFileTrigger(
463541
triggers.Types.beforeDeleteFile,
464542
handler,
@@ -490,6 +568,7 @@ ParseCloud.beforeDeleteFile = function (handler, validationHandler) {
490568
* @param {(Object|Function)} validator An optional function to help validating cloud code. This function can be an async function and should take one parameter a {@link Parse.Cloud.FileTriggerRequest}, or a {@link Parse.Cloud.ValidatorObject}.
491569
*/
492570
ParseCloud.afterDeleteFile = function (handler, validationHandler) {
571+
validateValidator(validationHandler);
493572
triggers.addFileTrigger(
494573
triggers.Types.afterDeleteFile,
495574
handler,
@@ -521,6 +600,7 @@ ParseCloud.afterDeleteFile = function (handler, validationHandler) {
521600
* @param {(Object|Function)} validator An optional function to help validating cloud code. This function can be an async function and should take one parameter a {@link Parse.Cloud.ConnectTriggerRequest}, or a {@link Parse.Cloud.ValidatorObject}.
522601
*/
523602
ParseCloud.beforeConnect = function (handler, validationHandler) {
603+
validateValidator(validationHandler);
524604
triggers.addConnectTrigger(
525605
triggers.Types.beforeConnect,
526606
handler,
@@ -585,6 +665,7 @@ ParseCloud.sendEmail = function (data) {
585665
* @param {(Object|Function)} validator An optional function to help validating cloud code. This function can be an async function and should take one parameter a {@link Parse.Cloud.TriggerRequest}, or a {@link Parse.Cloud.ValidatorObject}.
586666
*/
587667
ParseCloud.beforeSubscribe = function (parseClass, handler, validationHandler) {
668+
validateValidator(validationHandler);
588669
var className = getClassName(parseClass);
589670
triggers.addTrigger(
590671
triggers.Types.beforeSubscribe,
@@ -624,6 +705,7 @@ ParseCloud.onLiveQueryEvent = function (handler) {
624705
*/
625706
ParseCloud.afterLiveQueryEvent = function (parseClass, handler, validationHandler) {
626707
const className = getClassName(parseClass);
708+
validateValidator(validationHandler);
627709
triggers.addTrigger(
628710
triggers.Types.afterEvent,
629711
className,

0 commit comments

Comments
 (0)