Skip to content

Move field name validation logic out of mongo #1752

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 13, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 0 additions & 11 deletions spec/MongoTransform.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,17 +191,6 @@ describe('untransformObject', () => {
});
});

describe('transformKey', () => {
it('throws out _password', (done) => {
try {
transform.transformKey(dummySchema, '_User', '_password');
fail('should have thrown');
} catch (e) {
done();
}
});
});

describe('transform schema key changes', () => {

it('changes new pointer key', (done) => {
Expand Down
13 changes: 1 addition & 12 deletions src/Adapters/Storage/Mongo/MongoTransform.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,11 @@ var Parse = require('parse/node').Parse;
// in the value are converted to a mongo update form. Otherwise they are
// converted to static data.
//
// validate: true indicates that key names are to be validated.
//
// Returns an object with {key: key, value: value}.
function transformKeyValue(schema, className, restKey, restValue, {
inArray,
inObject,
update,
validate,
} = {}) {
// Check if the schema is known since it's a built-in field.
var key = restKey;
Expand Down Expand Up @@ -71,9 +68,6 @@ function transformKeyValue(schema, className, restKey, restValue, {
if (authDataMatch) {
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, 'can only query on ' + key);
}
if (validate && !key.match(/^[a-zA-Z][a-zA-Z0-9_\.]*$/)) {
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, 'invalid key name: ' + key);
}
}

// Handle special schema key changes
Expand Down Expand Up @@ -454,11 +448,6 @@ function untransformACL(mongoObject) {
return output;
}

// Transforms a key used in the REST API format to its mongo format.
function transformKey(schema, className, key) {
return transformKeyValue(schema, className, key, null, {validate: true}).key;
}

// A sentinel value that helper transformations return when they
// cannot perform a transformation
function CannotTransform() {}
Expand Down Expand Up @@ -1038,7 +1027,7 @@ var FileCoder = {
};

module.exports = {
transformKey,
transformKeyValue,
parseObjectToMongoObjectForCreate,
transformUpdate,
transformWhere,
Expand Down
19 changes: 16 additions & 3 deletions src/Controllers/DatabaseController.js
Original file line number Diff line number Diff line change
Expand Up @@ -618,9 +618,22 @@ DatabaseController.prototype.find = function(className, query, {
.then(schemaController => {
if (sort) {
mongoOptions.sort = {};
for (let key in sort) {
let mongoKey = this.transform.transformKey(schemaController, className, key);
mongoOptions.sort[mongoKey] = sort[key];
for (let fieldName in sort) {
// Parse.com treats queries on _created_at and _updated_at as if they were queries on createdAt and updatedAt,
// so duplicate that behaviour here.
if (fieldName === '_created_at') {
fieldName = 'createdAt';
sort['createdAt'] = sort['_created_at'];
} else if (fieldName === '_updated_at') {
fieldName = 'updatedAt';
sort['updatedAt'] = sort['_updated_at'];
}

if (!SchemaController.fieldNameIsValid(fieldName)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And here

throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, `Invalid field name: ${fieldName}.`);
}
const mongoKey = this.transform.transformKeyValue(schemaController, className, fieldName, null).key;
mongoOptions.sort[mongoKey] = sort[fieldName];
}
}
return (isMaster ? Promise.resolve() : schemaController.validatePermission(className, aclGroup, op))
Expand Down
12 changes: 7 additions & 5 deletions src/Controllers/SchemaController.js
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ class SchemaController {
this.data[schema.className] = schema.fields;
this.perms[schema.className] = schema.classLevelPermissions;
});

// Inject the in-memory classes
volatileClasses.forEach(className => {
this.data[className] = injectDefaultSchema({
Expand Down Expand Up @@ -466,15 +466,16 @@ class SchemaController {
// If 'freeze' is true, refuse to update the schema for this field.
validateField(className, fieldName, type, freeze) {
return this.reloadData().then(() => {
// Just to check that the fieldName is valid
this._collection.transform.transformKey(this, className, fieldName);

if( fieldName.indexOf(".") > 0 ) {
if (fieldName.indexOf(".") > 0) {
// subdocument key (x.y) => ok if x is of type 'object'
fieldName = fieldName.split(".")[ 0 ];
type = 'Object';
}

if (!fieldNameIsValid(fieldName)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here

throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, `Invalid field name: ${fieldName}.`);
}

let expected = this.data[className][fieldName];
if (expected) {
expected = (expected === 'map' ? 'Object' : expected);
Expand Down Expand Up @@ -847,6 +848,7 @@ function getObjectType(obj) {
export {
load,
classNameIsValid,
fieldNameIsValid,
invalidClassNameMessage,
buildMergedSchemaObject,
systemClasses,
Expand Down