Skip to content

Commit 7fd41f7

Browse files
author
Matt Gaunt
committed
Moving GCM endpoint over to using web push protocol
1 parent 8a8e900 commit 7fd41f7

File tree

2 files changed

+49
-80
lines changed

2 files changed

+49
-80
lines changed

index.js

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,6 @@ function sendNotification(endpoint, params) {
115115
}
116116
}
117117

118-
const isGCM = endpoint.indexOf('https://android.googleapis.com/gcm/send') === 0;
119-
120118
var urlParts = url.parse(endpoint);
121119
var options = {
122120
hostname: urlParts.hostname,
@@ -143,26 +141,13 @@ function sendNotification(endpoint, params) {
143141
requestPayload = encrypted.cipherText;
144142
}
145143

144+
var isGCM = endpoint.indexOf('https://android.googleapis.com/gcm/send') === 0;
146145
if (isGCM) {
147146
if (!gcmAPIKey) {
148147
console.warn('Attempt to send push notification to GCM endpoint, but no GCM key is defined'.bold.red);
149148
}
150149

151-
var endpointSections = endpoint.split('/');
152-
var subscriptionId = endpointSections[endpointSections.length - 1];
153-
154-
var gcmObj = {
155-
registration_ids: [ subscriptionId ],
156-
};
157-
if (requestPayload) {
158-
gcmObj['raw_data'] = requestPayload.toString('base64');
159-
}
160-
requestPayload = JSON.stringify(gcmObj);
161-
162-
options.path = options.path.substring(0, options.path.length - subscriptionId.length - 1);
163-
164150
options.headers['Authorization'] = 'key=' + gcmAPIKey;
165-
options.headers['Content-Type'] = 'application/json';
166151
}
167152

168153
if (vapid && !isGCM) {
@@ -188,7 +173,7 @@ function sendNotification(endpoint, params) {
188173
options.headers['Authorization'] = 'Bearer ' + jwt;
189174
var key = 'p256ecdsa=' + urlBase64.encode(vapid.publicKey);
190175
if (options.headers['Crypto-Key']) {
191-
options.headers['Crypto-Key'] += ',' + key;
176+
options.headers['Crypto-Key'] += ';' + key;
192177
} else {
193178
options.headers['Crypto-Key'] = key;
194179
}
@@ -204,7 +189,7 @@ function sendNotification(endpoint, params) {
204189
options.headers['Content-Length'] = requestPayload.length;
205190
}
206191

207-
var expectedStatusCode = isGCM ? 200 : 201;
192+
var expectedStatusCode = 201;
208193
var pushRequest = https.request(options, function(pushResponse) {
209194
var body = "";
210195

test/testSendNotification.js

Lines changed: 46 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -49,25 +49,25 @@ suite('sendNotification', function() {
4949
});
5050

5151
req.on('end', function() {
52-
assert.equal(req.headers['content-length'], body.length, 'Content-Length header correct');
52+
try {
53+
assert.equal(req.headers['content-length'], body.length, 'Content-Length header correct');
5354

54-
if (typeof TTL !== 'undefined') {
55-
assert.equal(req.headers['ttl'], TTL, 'TTL header correct');
56-
}
55+
if (typeof TTL !== 'undefined') {
56+
assert.equal(req.headers['ttl'], TTL, 'TTL header correct');
57+
}
5758

58-
if (typeof message !== 'undefined') {
59-
assert(body.length > 0);
59+
if (typeof message !== 'undefined') {
60+
assert(body.length > 0);
6061

61-
assert.equal(req.headers['encryption'].indexOf('keyid=p256dh;salt='), 0, 'Encryption header correct');
62-
var salt = req.headers['encryption'].substring('keyid=p256dh;salt='.length);
62+
assert.equal(req.headers['encryption'].indexOf('keyid=p256dh;salt='), 0, 'Encryption header correct');
63+
var salt = req.headers['encryption'].substring('keyid=p256dh;salt='.length);
6364

64-
if (!isGCM) {
6565
assert.equal(req.headers['content-type'], 'application/octet-stream', 'Content-Type header correct');
6666

67-
var keys = req.headers['crypto-key'].split(',');
67+
var keys = req.headers['crypto-key'].split(';');
6868
var appServerPublicKey = keys.find(function(key) {
69-
return key.indexOf('keyid=p256dh;dh=') === 0;
70-
}).substring('keyid=p256dh;dh='.length);
69+
return key.indexOf('dh=') === 0;
70+
}).substring('dh='.length);
7171

7272
assert.equal(req.headers['content-encoding'], 'aesgcm', 'Content-Encoding header correct');
7373

@@ -80,61 +80,45 @@ suite('sendNotification', function() {
8080
authSecret: urlBase64.encode(userAuth),
8181
padSize: 2,
8282
});
83-
} else {
84-
assert.equal(req.headers['crypto-key'].indexOf('keyid=p256dh;dh='), 0, 'Crypto-Key header correct');
85-
assert.equal(req.headers['content-encoding'], 'aesgcm', 'Content-Encoding header correct');
86-
var appServerPublicKey = req.headers['crypto-key'].substring('keyid=p256dh;dh='.length);
87-
88-
ece.saveKey('webpushKey', userCurve, 'P-256');
8983

90-
var raw_data = urlBase64.decode(JSON.parse(body).raw_data);
84+
assert(decrypted.equals(new Buffer(message)), "Cipher text correctly decoded");
85+
}
9186

92-
var decrypted = ece.decrypt(raw_data, {
93-
keyid: 'webpushKey',
94-
dh: appServerPublicKey,
95-
salt: salt,
96-
authSecret: urlBase64.encode(userAuth),
97-
padSize: 2,
87+
if (vapid) {
88+
var keys = req.headers['crypto-key'].split(';');
89+
var vapidKey = keys.find(function(key) {
90+
return key.indexOf('p256ecdsa=') === 0;
9891
});
92+
93+
assert.equal(vapidKey.indexOf('p256ecdsa='), 0, 'Crypto-Key header correct');
94+
var appServerVapidPublicKey = urlBase64.decode(vapidKey.substring('p256ecdsa='.length));
95+
96+
assert(appServerVapidPublicKey.equals(vapidKeys.publicKey));
97+
98+
var authorizationHeader = req.headers['authorization'];
99+
assert.equal(authorizationHeader.indexOf('Bearer '), 0, 'Authorization header correct');
100+
var jwt = authorizationHeader.substring('Bearer '.length);
101+
//assert(jws.verify(jwt, 'ES256', appServerVapidPublicKey)), 'JWT valid');
102+
var decoded = jws.decode(jwt);
103+
assert.equal(decoded.header.typ, 'JWT');
104+
assert.equal(decoded.header.alg, 'ES256');
105+
assert.equal(decoded.payload.aud, 'https://www.mozilla.org/');
106+
assert(decoded.payload.exp > Date.now() / 1000);
107+
assert.equal(decoded.payload.sub, 'mailto:[email protected]');
99108
}
100109

101-
assert(decrypted.equals(new Buffer(message)), "Cipher text correctly decoded");
102-
}
110+
if (isGCM) {
111+
assert.equal(req.headers['authorization'], 'key=my_gcm_key', 'Authorization header correct');
112+
}
103113

104-
if (vapid) {
105-
var keys = req.headers['crypto-key'].split(',');
106-
var vapidKey = keys.find(function(key) {
107-
return key.indexOf('p256ecdsa=') === 0;
108-
});
109-
110-
assert.equal(vapidKey.indexOf('p256ecdsa='), 0, 'Crypto-Key header correct');
111-
var appServerVapidPublicKey = urlBase64.decode(vapidKey.substring('p256ecdsa='.length));
112-
113-
assert(appServerVapidPublicKey.equals(vapidKeys.publicKey));
114-
115-
var authorizationHeader = req.headers['authorization'];
116-
assert.equal(authorizationHeader.indexOf('Bearer '), 0, 'Authorization header correct');
117-
var jwt = authorizationHeader.substring('Bearer '.length);
118-
//assert(jws.verify(jwt, 'ES256', appServerVapidPublicKey)), 'JWT valid');
119-
var decoded = jws.decode(jwt);
120-
assert.equal(decoded.header.typ, 'JWT');
121-
assert.equal(decoded.header.alg, 'ES256');
122-
assert.equal(decoded.payload.aud, 'https://www.mozilla.org/');
123-
assert(decoded.payload.exp > Date.now() / 1000);
124-
assert.equal(decoded.payload.sub, 'mailto:[email protected]');
125-
}
114+
res.writeHead(statusCode ? statusCode : 201);
126115

127-
if (isGCM) {
128-
assert.equal(JSON.stringify(JSON.parse(body).registration_ids), '["someSubscriptionID"]');
129-
assert.equal(req.headers['authorization'], 'key=my_gcm_key', 'Authorization header correct');
130-
assert.equal(req.headers['content-type'], 'application/json', 'Content-Type header correct');
131-
assert.equal(req.headers['content-length'], body.length, 'Content-Length header correct');
116+
res.end(statusCode !== 404 ? 'ok' : 'not found');
117+
} catch (err) {
118+
console.error(err);
119+
res.writeHead(500);
120+
res.end();
132121
}
133-
134-
res.writeHead(statusCode ? statusCode : 201);
135-
136-
res.end(statusCode !== 404 ? 'ok' : 'not found');
137-
138122
server.close();
139123
});
140124
});
@@ -334,7 +318,7 @@ suite('sendNotification', function() {
334318

335319
webPush.setGCMAPIKey('my_gcm_key');
336320

337-
return startServer(undefined, undefined, 200, true)
321+
return startServer(undefined, undefined, undefined, true)
338322
.then(function() {
339323
return webPush.sendNotification('https://android.googleapis.com/gcm/send/someSubscriptionID');
340324
})
@@ -356,7 +340,7 @@ suite('sendNotification', function() {
356340

357341
webPush.setGCMAPIKey('my_gcm_key');
358342

359-
return startServer('hello', undefined, 200, true)
343+
return startServer('hello', undefined, undefined, true)
360344
.then(function() {
361345
return webPush.sendNotification('https://android.googleapis.com/gcm/send/someSubscriptionID', {
362346
userPublicKey: urlBase64.encode(userPublicKey),
@@ -498,7 +482,7 @@ suite('sendNotification', function() {
498482

499483
webPush.setGCMAPIKey('my_gcm_key');
500484

501-
return startServer(undefined, undefined, 200, true)
485+
return startServer(undefined, undefined, undefined, true)
502486
.then(function() {
503487
return webPush.sendNotification('https://android.googleapis.com/gcm/send/someSubscriptionID', {
504488
vapid: {

0 commit comments

Comments
 (0)