Skip to content

Commit 3a0937f

Browse files
committed
Merge branch 'master' into snyk-upgrade-5e0fcce6684aa5bee2f660563eb8c08e
2 parents 58ab3e8 + abdfe61 commit 3a0937f

File tree

8 files changed

+84
-45
lines changed

8 files changed

+84
-45
lines changed

spec/CloudCode.spec.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,21 @@ describe('Cloud Code', () => {
216216
);
217217
});
218218

219+
it('test beforeSave with invalid field', async () => {
220+
Parse.Cloud.beforeSave('BeforeSaveChanged', function (req) {
221+
req.object.set('length', 0);
222+
});
223+
224+
const obj = new Parse.Object('BeforeSaveChanged');
225+
obj.set('foo', 'bar');
226+
try {
227+
await obj.save();
228+
fail('should not succeed');
229+
} catch (e) {
230+
expect(e.message).toBe('Invalid field name: length.');
231+
}
232+
});
233+
219234
it("test beforeSave changed object fail doesn't change object", async function () {
220235
Parse.Cloud.beforeSave('BeforeSaveChanged', function (req) {
221236
if (req.object.has('fail')) {

spec/ParseObject.spec.js

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -701,29 +701,24 @@ describe('Parse.Object testing', () => {
701701
});
702702
});
703703

704-
it('length attribute', function (done) {
704+
it('acl attribute', function (done) {
705705
Parse.User.signUp('bob', 'password').then(function (user) {
706706
const TestObject = Parse.Object.extend('TestObject');
707707
const obj = new TestObject({
708-
length: 5,
709708
ACL: new Parse.ACL(user), // ACLs cause things like validation to run
710709
});
711-
equal(obj.get('length'), 5);
712710
ok(obj.get('ACL') instanceof Parse.ACL);
713711

714712
obj.save().then(function (obj) {
715-
equal(obj.get('length'), 5);
716713
ok(obj.get('ACL') instanceof Parse.ACL);
717714

718715
const query = new Parse.Query(TestObject);
719716
query.get(obj.id).then(function (obj) {
720-
equal(obj.get('length'), 5);
721717
ok(obj.get('ACL') instanceof Parse.ACL);
722718

723719
const query = new Parse.Query(TestObject);
724720
query.find().then(function (results) {
725721
obj = results[0];
726-
equal(obj.get('length'), 5);
727722
ok(obj.get('ACL') instanceof Parse.ACL);
728723

729724
done();
@@ -733,6 +728,21 @@ describe('Parse.Object testing', () => {
733728
});
734729
});
735730

731+
it('cannot save object with invalid field', async () => {
732+
const invalidFields = ['className', 'length'];
733+
const promises = invalidFields.map(async field => {
734+
const obj = new TestObject();
735+
obj.set(field, 'bar');
736+
try {
737+
await obj.save();
738+
fail('should not succeed');
739+
} catch (e) {
740+
expect(e.message).toBe(`Invalid field name: ${field}.`);
741+
}
742+
});
743+
await Promise.all(promises);
744+
});
745+
736746
it('old attribute unset then unset', function (done) {
737747
const TestObject = Parse.Object.extend('TestObject');
738748
const obj = new TestObject();

spec/ParseQuery.spec.js

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2860,33 +2860,6 @@ describe('Parse.Query testing', () => {
28602860
});
28612861
});
28622862

2863-
it('object with length', function (done) {
2864-
const TestObject = Parse.Object.extend('TestObject');
2865-
const obj = new TestObject();
2866-
obj.set('length', 5);
2867-
equal(obj.get('length'), 5);
2868-
obj.save().then(
2869-
function () {
2870-
const query = new Parse.Query(TestObject);
2871-
query.find().then(
2872-
function (results) {
2873-
equal(results.length, 1);
2874-
equal(results[0].get('length'), 5);
2875-
done();
2876-
},
2877-
function (error) {
2878-
ok(false, error.message);
2879-
done();
2880-
}
2881-
);
2882-
},
2883-
function (error) {
2884-
ok(false, error.message);
2885-
done();
2886-
}
2887-
);
2888-
});
2889-
28902863
it('include user', function (done) {
28912864
Parse.User.signUp('bob', 'password', { age: 21 }).then(function (user) {
28922865
const TestObject = Parse.Object.extend('TestObject');

spec/batch.spec.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const serverURL1 = 'http://localhost:1234/1';
99
const serverURLNaked = 'http://localhost:1234/';
1010
const publicServerURL = 'http://domain.com/parse';
1111
const publicServerURLNaked = 'http://domain.com/';
12+
const publicServerURLLong = 'https://domain.com/something/really/long';
1213

1314
const headers = {
1415
'Content-Type': 'application/json',
@@ -24,6 +25,26 @@ describe('batch', () => {
2425
expect(internalURL).toEqual('/classes/Object');
2526
});
2627

28+
it('should return the proper url given a public url-only path', () => {
29+
const originalURL = '/something/really/long/batch';
30+
const internalURL = batch.makeBatchRoutingPathFunction(
31+
originalURL,
32+
serverURL,
33+
publicServerURLLong
34+
)('/parse/classes/Object');
35+
expect(internalURL).toEqual('/classes/Object');
36+
});
37+
38+
it('should return the proper url given a server url-only path', () => {
39+
const originalURL = '/parse/batch';
40+
const internalURL = batch.makeBatchRoutingPathFunction(
41+
originalURL,
42+
serverURL,
43+
publicServerURLLong
44+
)('/parse/classes/Object');
45+
expect(internalURL).toEqual('/classes/Object');
46+
});
47+
2748
it('should return the proper url same public/local endpoint', () => {
2849
const originalURL = '/parse/batch';
2950
const internalURL = batch.makeBatchRoutingPathFunction(

src/Controllers/DatabaseController.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,7 @@ class DatabaseController {
564564
}
565565
const rootFieldName = getRootFieldName(fieldName);
566566
if (
567-
!SchemaController.fieldNameIsValid(rootFieldName) &&
567+
!SchemaController.fieldNameIsValid(rootFieldName, className) &&
568568
!isSpecialUpdateKey(rootFieldName)
569569
) {
570570
throw new Parse.Error(
@@ -1213,7 +1213,7 @@ class DatabaseController {
12131213
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, `Cannot sort by ${fieldName}`);
12141214
}
12151215
const rootFieldName = getRootFieldName(fieldName);
1216-
if (!SchemaController.fieldNameIsValid(rootFieldName)) {
1216+
if (!SchemaController.fieldNameIsValid(rootFieldName, className)) {
12171217
throw new Parse.Error(
12181218
Parse.Error.INVALID_KEY_NAME,
12191219
`Invalid field name: ${fieldName}.`

src/Controllers/HooksController.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ function wrapToHTTPRequest(hook, key) {
242242
if (typeof result === 'object') {
243243
delete result.createdAt;
244244
delete result.updatedAt;
245+
delete result.className;
245246
}
246247
return { object: result };
247248
} else {

src/Controllers/SchemaController.js

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,8 @@ const requiredColumns = Object.freeze({
155155
_Role: ['name', 'ACL'],
156156
});
157157

158+
const invalidColumns = ['length'];
159+
158160
const systemClasses = Object.freeze([
159161
'_User',
160162
'_Installation',
@@ -422,18 +424,24 @@ function classNameIsValid(className: string): boolean {
422424
// Be a join table OR
423425
joinClassRegex.test(className) ||
424426
// Include only alpha-numeric and underscores, and not start with an underscore or number
425-
fieldNameIsValid(className)
427+
fieldNameIsValid(className, className)
426428
);
427429
}
428430

429431
// Valid fields must be alpha-numeric, and not start with an underscore or number
430-
function fieldNameIsValid(fieldName: string): boolean {
431-
return classAndFieldRegex.test(fieldName);
432+
// must not be a reserved key
433+
function fieldNameIsValid(fieldName: string, className: string): boolean {
434+
if (className && className !== '_Hooks') {
435+
if (fieldName === 'className') {
436+
return false;
437+
}
438+
}
439+
return classAndFieldRegex.test(fieldName) && !invalidColumns.includes(fieldName);
432440
}
433441

434442
// Checks that it's not trying to clobber one of the default fields of the class.
435443
function fieldNameIsValidForClass(fieldName: string, className: string): boolean {
436-
if (!fieldNameIsValid(fieldName)) {
444+
if (!fieldNameIsValid(fieldName, className)) {
437445
return false;
438446
}
439447
if (defaultColumns._Default[fieldName]) {
@@ -976,7 +984,7 @@ export default class SchemaController {
976984
) {
977985
for (const fieldName in fields) {
978986
if (existingFieldNames.indexOf(fieldName) < 0) {
979-
if (!fieldNameIsValid(fieldName)) {
987+
if (!fieldNameIsValid(fieldName, className)) {
980988
return {
981989
code: Parse.Error.INVALID_KEY_NAME,
982990
error: 'invalid field name: ' + fieldName,
@@ -1060,7 +1068,7 @@ export default class SchemaController {
10601068
fieldName = fieldName.split('.')[0];
10611069
type = 'Object';
10621070
}
1063-
if (!fieldNameIsValid(fieldName)) {
1071+
if (!fieldNameIsValid(fieldName, className)) {
10641072
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, `Invalid field name: ${fieldName}.`);
10651073
}
10661074

@@ -1154,7 +1162,7 @@ export default class SchemaController {
11541162
}
11551163

11561164
fieldNames.forEach(fieldName => {
1157-
if (!fieldNameIsValid(fieldName)) {
1165+
if (!fieldNameIsValid(fieldName, className)) {
11581166
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, `invalid field name: ${fieldName}`);
11591167
}
11601168
//Don't allow deleting the default fields.

src/batch.js

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,23 @@ function makeBatchRoutingPathFunction(originalUrl, serverURL, publicServerURL) {
3636
if (serverURL && publicServerURL && serverURL.path != publicServerURL.path) {
3737
const localPath = serverURL.path;
3838
const publicPath = publicServerURL.path;
39+
3940
// Override the api prefix
4041
apiPrefix = localPath;
4142
return function (requestPath) {
42-
// Build the new path by removing the public path
43-
// and joining with the local path
44-
const newPath = path.posix.join('/', localPath, '/', requestPath.slice(publicPath.length));
43+
// Figure out which server url was used by figuring out which
44+
// path more closely matches requestPath
45+
const startsWithLocal = requestPath.startsWith(localPath);
46+
const startsWithPublic = requestPath.startsWith(publicPath);
47+
const pathLengthToUse =
48+
startsWithLocal && startsWithPublic
49+
? Math.max(localPath.length, publicPath.length)
50+
: startsWithLocal
51+
? localPath.length
52+
: publicPath.length;
53+
54+
const newPath = path.posix.join('/', localPath, '/', requestPath.slice(pathLengthToUse));
55+
4556
// Use the method for local routing
4657
return makeRoutablePath(newPath);
4758
};

0 commit comments

Comments
 (0)