Skip to content

Commit 598cb84

Browse files
authored
fix: Validate push notification payload; fixes a security vulnerability in which the adapter can crash Parse Server due to an invalid push notification payload (#217)
1 parent 346781d commit 598cb84

File tree

4 files changed

+38
-8
lines changed

4 files changed

+38
-8
lines changed

spec/APNS.spec.js

+20-6
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ describe('APNS', () => {
104104

105105
var prodApnsConnection = apns.providers[0];
106106
expect(prodApnsConnection.index).toBe(0);
107-
107+
108108
// TODO: Remove this checking onec we inject APNS
109109
var prodApnsOptions = prodApnsConnection.client.config;
110110
expect(prodApnsOptions.cert).toBe(args[1].cert);
@@ -239,7 +239,7 @@ describe('APNS', () => {
239239
expect(notification.pushType).toEqual('alert');
240240
done();
241241
});
242-
242+
243243
it('can generate APNS notification from raw data', (done) => {
244244
//Mock request data
245245
let data = {
@@ -259,17 +259,17 @@ describe('APNS', () => {
259259
let collapseId = "collapseIdentifier";
260260
let pushType = "background";
261261
let priority = 5;
262-
262+
263263
let notification = APNS._generateNotification(data, { expirationTime: expirationTime, collapseId: collapseId, pushType: pushType, priority: priority });
264-
264+
265265
expect(notification.expiry).toEqual(Math.round(expirationTime / 1000));
266266
expect(notification.collapseId).toEqual(collapseId);
267267
expect(notification.pushType).toEqual(pushType);
268268
expect(notification.priority).toEqual(priority);
269-
269+
270270
let stringifiedJSON = notification.compile();
271271
let jsonObject = JSON.parse(stringifiedJSON);
272-
272+
273273
expect(jsonObject.aps.alert).toEqual({ "loc-key" : "GAME_PLAY_REQUEST_FORMAT", "loc-args" : [ "Jenna", "Frank"] });
274274
expect(jsonObject.aps.badge).toEqual(100);
275275
expect(jsonObject.aps.sound).toEqual('test');
@@ -315,6 +315,20 @@ describe('APNS', () => {
315315
done();
316316
});
317317

318+
it('does log on invalid APNS notification', async () => {
319+
const args = {
320+
cert: new Buffer('testCert'),
321+
key: new Buffer('testKey'),
322+
production: true,
323+
topic: 'topic'
324+
};
325+
const log = require('npmlog');
326+
const spy = spyOn(log, 'warn');
327+
const apns = new APNS(args);
328+
apns.send();
329+
expect(spy).toHaveBeenCalled();
330+
});
331+
318332
it('can send APNS notification', (done) => {
319333
let args = {
320334
cert: new Buffer('testCert'),

spec/GCM.spec.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ function mockSender(gcm) {
1010
{"error":"InvalidRegistration"},
1111
{"error":"InvalidRegistration"},
1212
{"error":"InvalidRegistration"}] }*/
13-
13+
1414
let tokens = options.registrationTokens;
1515
const response = {
1616
multicast_id: 7680139367771848000,
@@ -58,6 +58,14 @@ describe('GCM', () => {
5858
done();
5959
});
6060

61+
it('does log on invalid APNS notification', async () => {
62+
const log = require('npmlog');
63+
const spy = spyOn(log, 'warn');
64+
const gcm = new GCM({apiKey: 'apiKey'});
65+
gcm.send();
66+
expect(spy).toHaveBeenCalled();
67+
});
68+
6169
it('can generate GCM Payload without expiration time', (done) => {
6270
//Mock request data
6371
var requestData = {

src/APNS.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,11 @@ export class APNS {
7070
* @returns {Object} A promise which is resolved immediately
7171
*/
7272
send(data, allDevices) {
73-
let coreData = data.data;
73+
let coreData = data && data.data;
74+
if (!coreData || !allDevices || !Array.isArray(allDevices)) {
75+
log.warn(LOG_PREFIX, 'invalid push payload');
76+
return;
77+
}
7478
let expirationTime = data['expiration_time'] || coreData['expiration_time'];
7579
let collapseId = data['collapse_id'] || coreData['collapse_id'];
7680
let pushType = data['push_type'] || coreData['push_type'];

src/GCM.js

+4
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ GCM.GCMRegistrationTokensMax = GCMRegistrationTokensMax;
2626
* @returns {Object} A promise which is resolved after we get results from gcm
2727
*/
2828
GCM.prototype.send = function(data, devices) {
29+
if (!data || !devices || !Array.isArray(devices)) {
30+
log.warn(LOG_PREFIX, 'invalid push payload');
31+
return;
32+
}
2933
let pushId = randomString(10);
3034
// Make a new array
3135
devices=devices.slice(0);

0 commit comments

Comments
 (0)