Add push parameter checking and query installation
This commit is contained in:
2
index.js
2
index.js
@@ -111,7 +111,7 @@ function ParseServer(args) {
|
||||
router.merge(require('./sessions'));
|
||||
router.merge(require('./roles'));
|
||||
router.merge(require('./analytics'));
|
||||
router.merge(require('./push'));
|
||||
router.merge(require('./push').router);
|
||||
router.merge(require('./installations'));
|
||||
router.merge(require('./functions'));
|
||||
router.merge(require('./schemas'));
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
"mongodb": "~2.1.0",
|
||||
"multer": "^1.1.0",
|
||||
"parse": "^1.7.0",
|
||||
"moment": "^2.11.1",
|
||||
"request": "^2.65.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -30,7 +31,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"pretest": "MONGODB_VERSION=${MONGODB_VERSION:=3.0.8} mongodb-runner start",
|
||||
"test": "TESTING=1 ./node_modules/.bin/istanbul cover --include-all-sources -x **/spec/** ./node_modules/.bin/jasmine",
|
||||
"test": "NODE_ENV=test TESTING=1 ./node_modules/.bin/istanbul cover --include-all-sources -x **/spec/** ./node_modules/.bin/jasmine",
|
||||
"posttest": "mongodb-runner stop",
|
||||
"start": "./bin/parse-server"
|
||||
},
|
||||
|
||||
125
push.js
125
push.js
@@ -2,17 +2,124 @@
|
||||
|
||||
var Parse = require('parse/node').Parse,
|
||||
PromiseRouter = require('./PromiseRouter'),
|
||||
rest = require('./rest');
|
||||
rest = require('./rest'),
|
||||
moment = require('moment');
|
||||
|
||||
var router = new PromiseRouter();
|
||||
var validPushTypes = ['ios', 'android'];
|
||||
|
||||
|
||||
|
||||
function notImplementedYet(req) {
|
||||
throw new Parse.Error(Parse.Error.COMMAND_UNAVAILABLE,
|
||||
'This path is not implemented yet.');
|
||||
function handlePushWithoutQueue(req) {
|
||||
validateMasterKey(req);
|
||||
var where = getQueryCondition(req);
|
||||
validateDeviceType(where);
|
||||
// Replace the expiration_time with a valid Unix epoch milliseconds time
|
||||
req.body['expiration_time'] = getExpirationTime(req);
|
||||
return rest.find(req.config, req.auth, '_Installation', where).then(function(response) {
|
||||
throw new Parse.Error(Parse.Error.COMMAND_UNAVAILABLE,
|
||||
'This path is not implemented yet.');
|
||||
});
|
||||
}
|
||||
|
||||
router.route('POST','/push', notImplementedYet);
|
||||
/**
|
||||
* Check whether the deviceType parameter in qury condition is valid or not.
|
||||
* @param {Object} where A query condition
|
||||
*/
|
||||
function validateDeviceType(where) {
|
||||
var where = where || {};
|
||||
var deviceTypeField = where.deviceType || {};
|
||||
var deviceTypes = [];
|
||||
if (typeof deviceTypeField === 'string') {
|
||||
deviceTypes.push(deviceTypeField);
|
||||
} else if (typeof deviceTypeField['$in'] === 'array') {
|
||||
deviceTypes.concat(deviceTypeField['$in']);
|
||||
}
|
||||
for (var i = 0; i < deviceTypes.length; i++) {
|
||||
var deviceType = deviceTypes[i];
|
||||
if (validPushTypes.indexOf(deviceType) < 0) {
|
||||
throw new Parse.Error(Parse.Error.PUSH_MISCONFIGURED,
|
||||
deviceType + ' is not supported push type.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = router;
|
||||
/**
|
||||
* Get expiration time from the request body.
|
||||
* @param {Object} request A request object
|
||||
* @returns {Number|undefined} The expiration time if it exists in the request
|
||||
*/
|
||||
function getExpirationTime(req) {
|
||||
var body = req.body || {};
|
||||
var hasExpirationTime = !!body['expiration_time'];
|
||||
if (!hasExpirationTime) {
|
||||
return;
|
||||
}
|
||||
var expirationTimeParam = body['expiration_time'];
|
||||
var expirationTime;
|
||||
if (typeof expirationTimeParam === 'number') {
|
||||
expirationTime = new Date(expirationTimeParam * 1000);
|
||||
} else if (typeof expirationTimeParam === 'string') {
|
||||
expirationTime = new Date(expirationTimeParam);
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.PUSH_MISCONFIGURED,
|
||||
body['expiration_time'] + ' is not valid time.');
|
||||
}
|
||||
// Check expirationTime is valid or not, if it is not valid, expirationTime is NaN
|
||||
if (!isFinite(expirationTime)) {
|
||||
throw new Parse.Error(Parse.Error.PUSH_MISCONFIGURED,
|
||||
body['expiration_time'] + ' is not valid time.');
|
||||
}
|
||||
return expirationTime.valueOf();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get query condition from the request body.
|
||||
* @param {Object} request A request object
|
||||
* @returns {Object} The query condition, the where field in a query api call
|
||||
*/
|
||||
function getQueryCondition(req) {
|
||||
var body = req.body || {};
|
||||
var hasWhere = typeof body.where !== 'undefined';
|
||||
var hasChannels = typeof body.channels !== 'undefined';
|
||||
|
||||
var where;
|
||||
if (hasWhere && hasChannels) {
|
||||
throw new Parse.Error(Parse.Error.PUSH_MISCONFIGURED,
|
||||
'Channels and query can not be set at the same time.');
|
||||
} else if (hasWhere) {
|
||||
where = body.where;
|
||||
} else if (hasChannels) {
|
||||
where = {
|
||||
"channels": {
|
||||
"$in": body.channels
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.PUSH_MISCONFIGURED,
|
||||
'Channels and query should be set at least one.');
|
||||
}
|
||||
return where;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the api call has master key or not.
|
||||
* @param {Object} request A request object
|
||||
*/
|
||||
function validateMasterKey(req) {
|
||||
if (req.info.masterKey !== req.config.masterKey) {
|
||||
throw new Parse.Error(Parse.Error.PUSH_MISCONFIGURED,
|
||||
'Master key is invalid, you should only use master key to send push');
|
||||
}
|
||||
}
|
||||
|
||||
var router = new PromiseRouter();
|
||||
router.route('POST','/push', handlePushWithoutQueue);
|
||||
|
||||
module.exports = {
|
||||
router: router
|
||||
}
|
||||
|
||||
if (typeof process !== 'undefined' && process.env.NODE_ENV === 'test') {
|
||||
module.exports.getQueryCondition = getQueryCondition;
|
||||
module.exports.validateMasterKey = validateMasterKey;
|
||||
module.exports.getExpirationTime = getExpirationTime;
|
||||
module.exports.validateDeviceType = validateDeviceType;
|
||||
}
|
||||
|
||||
206
spec/push.spec.js
Normal file
206
spec/push.spec.js
Normal file
@@ -0,0 +1,206 @@
|
||||
var push = require('../push');
|
||||
|
||||
describe('push', () => {
|
||||
it('can check valid master key of request', (done) => {
|
||||
// Make mock request
|
||||
var request = {
|
||||
info: {
|
||||
masterKey: 'masterKey'
|
||||
},
|
||||
config: {
|
||||
masterKey: 'masterKey'
|
||||
}
|
||||
}
|
||||
|
||||
expect(() => {
|
||||
push.validateMasterKey(request);
|
||||
}).not.toThrow();
|
||||
done();
|
||||
});
|
||||
|
||||
it('can check invalid master key of request', (done) => {
|
||||
// Make mock request
|
||||
var request = {
|
||||
info: {
|
||||
masterKey: 'masterKey'
|
||||
},
|
||||
config: {
|
||||
masterKey: 'masterKeyAgain'
|
||||
}
|
||||
}
|
||||
|
||||
expect(() => {
|
||||
push.validateMasterKey(request);
|
||||
}).toThrow();
|
||||
done();
|
||||
});
|
||||
|
||||
it('can get query condition when channels is set', (done) => {
|
||||
// Make mock request
|
||||
var request = {
|
||||
body: {
|
||||
channels: ['Giants', 'Mets']
|
||||
}
|
||||
}
|
||||
|
||||
var where = push.getQueryCondition(request);
|
||||
expect(where).toEqual({
|
||||
'channels': {
|
||||
'$in': ['Giants', 'Mets']
|
||||
}
|
||||
});
|
||||
done();
|
||||
});
|
||||
|
||||
it('can get query condition when where is set', (done) => {
|
||||
// Make mock request
|
||||
var request = {
|
||||
body: {
|
||||
'where': {
|
||||
'injuryReports': true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var where = push.getQueryCondition(request);
|
||||
expect(where).toEqual({
|
||||
'injuryReports': true
|
||||
});
|
||||
done();
|
||||
});
|
||||
|
||||
it('can get query condition when nothing is set', (done) => {
|
||||
// Make mock request
|
||||
var request = {
|
||||
body: {
|
||||
}
|
||||
}
|
||||
|
||||
expect(function() {
|
||||
push.getQueryCondition(request);
|
||||
}).toThrow();
|
||||
done();
|
||||
});
|
||||
|
||||
it('can throw on getQueryCondition when channels and where are set', (done) => {
|
||||
// Make mock request
|
||||
var request = {
|
||||
body: {
|
||||
'channels': {
|
||||
'$in': ['Giants', 'Mets']
|
||||
},
|
||||
'where': {
|
||||
'injuryReports': true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expect(function() {
|
||||
push.getQueryCondition(request);
|
||||
}).toThrow();
|
||||
done();
|
||||
});
|
||||
|
||||
it('can validate device type when no device type is set', (done) => {
|
||||
// Make query condition
|
||||
var where = {
|
||||
}
|
||||
|
||||
expect(function(){
|
||||
push.validateDeviceType(where);
|
||||
}).not.toThrow();
|
||||
done();
|
||||
});
|
||||
|
||||
it('can validate device type when single valid device type is set', (done) => {
|
||||
// Make query condition
|
||||
var where = {
|
||||
'deviceType': 'ios'
|
||||
}
|
||||
|
||||
expect(function(){
|
||||
push.validateDeviceType(where);
|
||||
}).not.toThrow();
|
||||
done();
|
||||
});
|
||||
|
||||
it('can validate device type when multiple valid device types are set', (done) => {
|
||||
// Make query condition
|
||||
var where = {
|
||||
'deviceType': {
|
||||
'$in': ['android', 'ios']
|
||||
}
|
||||
}
|
||||
|
||||
expect(function(){
|
||||
push.validateDeviceType(where);
|
||||
}).not.toThrow();
|
||||
done();
|
||||
});
|
||||
|
||||
it('can throw on validateDeviceType when single invalid device type is set', (done) => {
|
||||
// Make query condition
|
||||
var where = {
|
||||
'deviceType': 'osx'
|
||||
}
|
||||
|
||||
expect(function(){
|
||||
push.validateDeviceType(where);
|
||||
}).toThrow();
|
||||
done();
|
||||
});
|
||||
|
||||
it('can throw on validateDeviceType when single invalid device type is set', (done) => {
|
||||
// Make query condition
|
||||
var where = {
|
||||
'deviceType': 'osx'
|
||||
}
|
||||
|
||||
expect(function(){
|
||||
push.validateDeviceType(where)
|
||||
}).toThrow();
|
||||
done();
|
||||
});
|
||||
|
||||
it('can get expiration time in string format', (done) => {
|
||||
// Make mock request
|
||||
var timeStr = '2015-03-19T22:05:08Z';
|
||||
var request = {
|
||||
body: {
|
||||
'expiration_time': timeStr
|
||||
}
|
||||
}
|
||||
|
||||
var time = push.getExpirationTime(request);
|
||||
expect(time).toEqual(new Date(timeStr).valueOf());
|
||||
done();
|
||||
});
|
||||
|
||||
it('can get expiration time in number format', (done) => {
|
||||
// Make mock request
|
||||
var timeNumber = 1426802708;
|
||||
var request = {
|
||||
body: {
|
||||
'expiration_time': timeNumber
|
||||
}
|
||||
}
|
||||
|
||||
var time = push.getExpirationTime(request);
|
||||
expect(time).toEqual(timeNumber * 1000);
|
||||
done();
|
||||
});
|
||||
|
||||
it('can throw on getExpirationTime in invalid format', (done) => {
|
||||
// Make mock request
|
||||
var request = {
|
||||
body: {
|
||||
'expiration_time': 'abcd'
|
||||
}
|
||||
}
|
||||
|
||||
expect(function(){
|
||||
push.getExpirationTime(request);
|
||||
}).toThrow();
|
||||
done();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user