Merge remote-tracking branch 'upstream/master' into test-configurations
This commit is contained in:
@@ -1,5 +1,12 @@
|
|||||||
## Parse Server Changelog
|
## Parse Server Changelog
|
||||||
|
|
||||||
|
### 2.1.2 (2/19/2016)
|
||||||
|
|
||||||
|
* Change: The S3 file adapter constructor requires a bucket name
|
||||||
|
* Fix: Parse Query should throw if improperly encoded
|
||||||
|
* Fix: Issue where roles were not used in some requests
|
||||||
|
* Fix: serverURL will no longer default to api.parse.com/1
|
||||||
|
|
||||||
### 2.1.1 (2/18/2016)
|
### 2.1.1 (2/18/2016)
|
||||||
|
|
||||||
* Experimental: Schemas API support for DELETE operations
|
* Experimental: Schemas API support for DELETE operations
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ describe('Parse Role testing', () => {
|
|||||||
}).then((x) => {
|
}).then((x) => {
|
||||||
x.set('foo', 'baz');
|
x.set('foo', 'baz');
|
||||||
// This should fail:
|
// This should fail:
|
||||||
return x.save();
|
return x.save({},{sessionToken: ""});
|
||||||
}).then((x) => {
|
}).then((x) => {
|
||||||
fail('Should not have been able to save.');
|
fail('Should not have been able to save.');
|
||||||
}, (e) => {
|
}, (e) => {
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ var cache = require('../src/cache');
|
|||||||
var Config = require('../src/Config');
|
var Config = require('../src/Config');
|
||||||
var rest = require('../src/rest');
|
var rest = require('../src/rest');
|
||||||
|
|
||||||
|
var querystring = require('querystring');
|
||||||
|
var request = require('request');
|
||||||
|
|
||||||
var config = new Config('test');
|
var config = new Config('test');
|
||||||
var nobody = auth.nobody(config);
|
var nobody = auth.nobody(config);
|
||||||
|
|
||||||
@@ -92,4 +95,49 @@ describe('rest query', () => {
|
|||||||
}).catch((error) => { console.log(error); });
|
}).catch((error) => { console.log(error); });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('query with wrongly encoded parameter', (done) => {
|
||||||
|
rest.create(config, nobody, 'TestParameterEncode', {foo: 'bar'}
|
||||||
|
).then(() => {
|
||||||
|
return rest.create(config, nobody,
|
||||||
|
'TestParameterEncode', {foo: 'baz'});
|
||||||
|
}).then(() => {
|
||||||
|
var headers = {
|
||||||
|
'X-Parse-Application-Id': 'test',
|
||||||
|
'X-Parse-REST-API-Key': 'rest'
|
||||||
|
};
|
||||||
|
request.get({
|
||||||
|
headers: headers,
|
||||||
|
url: 'http://localhost:8378/1/classes/TestParameterEncode?'
|
||||||
|
+ querystring.stringify({
|
||||||
|
where: '{"foo":{"$ne": "baz"}}',
|
||||||
|
limit: 1
|
||||||
|
}).replace('=', '%3D'),
|
||||||
|
}, (error, response, body) => {
|
||||||
|
expect(error).toBe(null);
|
||||||
|
var b = JSON.parse(body);
|
||||||
|
expect(b.code).toEqual(Parse.Error.INVALID_QUERY);
|
||||||
|
expect(b.error).toEqual('Improper encode of parameter');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
}).then(() => {
|
||||||
|
var headers = {
|
||||||
|
'X-Parse-Application-Id': 'test',
|
||||||
|
'X-Parse-REST-API-Key': 'rest'
|
||||||
|
};
|
||||||
|
request.get({
|
||||||
|
headers: headers,
|
||||||
|
url: 'http://localhost:8378/1/classes/TestParameterEncode?'
|
||||||
|
+ querystring.stringify({
|
||||||
|
limit: 1
|
||||||
|
}).replace('=', '%3D'),
|
||||||
|
}, (error, response, body) => {
|
||||||
|
expect(error).toBe(null);
|
||||||
|
var b = JSON.parse(body);
|
||||||
|
expect(b.code).toEqual(Parse.Error.INVALID_QUERY);
|
||||||
|
expect(b.error).toEqual('Improper encode of parameter');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ Auth.prototype.getUserRoles = function() {
|
|||||||
return Promise.resolve(this.userRoles);
|
return Promise.resolve(this.userRoles);
|
||||||
}
|
}
|
||||||
if (this.rolePromise) {
|
if (this.rolePromise) {
|
||||||
return rolePromise;
|
return this.rolePromise;
|
||||||
}
|
}
|
||||||
this.rolePromise = this._loadRoles();
|
this.rolePromise = this._loadRoles();
|
||||||
return this.rolePromise;
|
return this.rolePromise;
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ function RestWrite(config, auth, className, query, data, originalData) {
|
|||||||
this.auth = auth;
|
this.auth = auth;
|
||||||
this.className = className;
|
this.className = className;
|
||||||
this.storage = {};
|
this.storage = {};
|
||||||
|
this.runOptions = {};
|
||||||
|
|
||||||
if (!query && data.objectId) {
|
if (!query && data.objectId) {
|
||||||
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, 'objectId ' +
|
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, 'objectId ' +
|
||||||
@@ -66,6 +67,8 @@ function RestWrite(config, auth, className, query, data, originalData) {
|
|||||||
// status and location are optional.
|
// status and location are optional.
|
||||||
RestWrite.prototype.execute = function() {
|
RestWrite.prototype.execute = function() {
|
||||||
return Promise.resolve().then(() => {
|
return Promise.resolve().then(() => {
|
||||||
|
return this.getUserAndRoleACL();
|
||||||
|
}).then(() => {
|
||||||
return this.validateSchema();
|
return this.validateSchema();
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
return this.handleInstallation();
|
return this.handleInstallation();
|
||||||
@@ -88,6 +91,25 @@ RestWrite.prototype.execute = function() {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Uses the Auth object to get the list of roles, adds the user id
|
||||||
|
RestWrite.prototype.getUserAndRoleACL = function() {
|
||||||
|
if (this.auth.isMaster) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.runOptions.acl = ['*'];
|
||||||
|
|
||||||
|
if( this.auth.user ){
|
||||||
|
return this.auth.getUserRoles().then((roles) => {
|
||||||
|
roles.push(this.auth.user.id);
|
||||||
|
this.runOptions.acl = this.runOptions.acl.concat(roles);
|
||||||
|
return Promise.resolve();
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Validates this operation against the schema.
|
// Validates this operation against the schema.
|
||||||
RestWrite.prototype.validateSchema = function() {
|
RestWrite.prototype.validateSchema = function() {
|
||||||
return this.config.database.validateObject(this.className, this.data);
|
return this.config.database.validateObject(this.className, this.data);
|
||||||
@@ -690,18 +712,10 @@ RestWrite.prototype.runDatabaseOperation = function() {
|
|||||||
throw new Parse.Error(Parse.Error.INVALID_ACL, 'Invalid ACL.');
|
throw new Parse.Error(Parse.Error.INVALID_ACL, 'Invalid ACL.');
|
||||||
}
|
}
|
||||||
|
|
||||||
var options = {};
|
|
||||||
if (!this.auth.isMaster) {
|
|
||||||
options.acl = ['*'];
|
|
||||||
if (this.auth.user) {
|
|
||||||
options.acl.push(this.auth.user.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.query) {
|
if (this.query) {
|
||||||
// Run an update
|
// Run an update
|
||||||
return this.config.database.update(
|
return this.config.database.update(
|
||||||
this.className, this.query, this.data, options).then((resp) => {
|
this.className, this.query, this.data, this.runOptions).then((resp) => {
|
||||||
this.response = resp;
|
this.response = resp;
|
||||||
this.response.updatedAt = this.updatedAt;
|
this.response.updatedAt = this.updatedAt;
|
||||||
});
|
});
|
||||||
@@ -714,7 +728,7 @@ RestWrite.prototype.runDatabaseOperation = function() {
|
|||||||
this.data.ACL = ACL;
|
this.data.ACL = ACL;
|
||||||
}
|
}
|
||||||
// Run a create
|
// Run a create
|
||||||
return this.config.database.create(this.className, this.data, options)
|
return this.config.database.create(this.className, this.data, this.runOptions)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
var resp = {
|
var resp = {
|
||||||
objectId: this.data.objectId,
|
objectId: this.data.objectId,
|
||||||
|
|||||||
@@ -2,11 +2,22 @@
|
|||||||
import PromiseRouter from '../PromiseRouter';
|
import PromiseRouter from '../PromiseRouter';
|
||||||
import rest from '../rest';
|
import rest from '../rest';
|
||||||
|
|
||||||
|
import url from 'url';
|
||||||
|
|
||||||
export class ClassesRouter {
|
export class ClassesRouter {
|
||||||
// Returns a promise that resolves to a {response} object.
|
// Returns a promise that resolves to a {response} object.
|
||||||
handleFind(req) {
|
handleFind(req) {
|
||||||
let body = Object.assign(req.body, req.query);
|
let body = Object.assign(req.body, req.query);
|
||||||
let options = {};
|
let options = {};
|
||||||
|
let allowConstraints = ['skip', 'limit', 'order', 'count', 'keys',
|
||||||
|
'include', 'redirectClassNameForKey', 'where'];
|
||||||
|
|
||||||
|
for (var key in body) {
|
||||||
|
if (allowConstraints.indexOf(key) === -1) {
|
||||||
|
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Improper encode of parameter');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (body.skip) {
|
if (body.skip) {
|
||||||
options.skip = Number(body.skip);
|
options.skip = Number(body.skip);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ function ParseServer({
|
|||||||
facebookAppIds = [],
|
facebookAppIds = [],
|
||||||
enableAnonymousUsers = true,
|
enableAnonymousUsers = true,
|
||||||
oauth = {},
|
oauth = {},
|
||||||
serverURL,
|
serverURL = '',
|
||||||
}) {
|
}) {
|
||||||
if (!appId || !masterKey) {
|
if (!appId || !masterKey) {
|
||||||
throw 'You must provide an appId and masterKey!';
|
throw 'You must provide an appId and masterKey!';
|
||||||
@@ -128,9 +128,7 @@ function ParseServer({
|
|||||||
|
|
||||||
// Initialize the node client SDK automatically
|
// Initialize the node client SDK automatically
|
||||||
Parse.initialize(appId, javascriptKey, masterKey);
|
Parse.initialize(appId, javascriptKey, masterKey);
|
||||||
if (serverURL) {
|
Parse.serverURL = serverURL;
|
||||||
Parse.serverURL = serverURL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This app serves the Parse API directly.
|
// This app serves the Parse API directly.
|
||||||
// It's the equivalent of https://api.parse.com/1 in the hosted Parse API.
|
// It's the equivalent of https://api.parse.com/1 in the hosted Parse API.
|
||||||
|
|||||||
@@ -56,12 +56,19 @@ function del(config, auth, className, objectId) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
return Promise.resolve({});
|
return Promise.resolve({});
|
||||||
|
}).then(() => {
|
||||||
|
if (!auth.isMaster) {
|
||||||
|
return auth.getUserRoles();
|
||||||
|
}else{
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
var options = {};
|
var options = {};
|
||||||
if (!auth.isMaster) {
|
if (!auth.isMaster) {
|
||||||
options.acl = ['*'];
|
options.acl = ['*'];
|
||||||
if (auth.user) {
|
if (auth.user) {
|
||||||
options.acl.push(auth.user.id);
|
options.acl.push(auth.user.id);
|
||||||
|
options.acl = options.acl.concat(auth.userRoles);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user