Skip to content
This repository has been archived by the owner on Apr 23, 2021. It is now read-only.

Allow sending with no payload, plus some small fixes #17

Merged
merged 3 commits into from
Apr 28, 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
2 changes: 0 additions & 2 deletions src/encrypt.js
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,4 @@ function encryptPayload(plaintext, contentEncryptionKey, nonce) {
return Buffer.concat([result, cipher.getAuthTag()]);
}

// All functions are exported here to make them testable, but only `encrypt` is
// re-exported by `index.js` as part of the public API.
module.exports = encrypt;
3 changes: 2 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@ const push = require('./push');
*/
module.exports = {
encrypt: encrypt,
sendWebPush: push
sendWebPush: push.sendWebPush,
setGCMAPIKey: push.setGCMAPIKey
};
47 changes: 32 additions & 15 deletions src/push.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ const encrypt = require('./encrypt');
const GCM_URL = 'https://android.googleapis.com/gcm/send';
const TEMP_GCM_URL = 'https://gcm-http.googleapis.com/gcm';

let gcmAuthToken;

/**
* Set the key to use in the Authentication header for GCM requests
* @param {String} key The API key to use
*/
function setGCMAPIKey(key) {
gcmAuthToken = key;
}

/**
* URL safe Base64 encoder
*
Expand All @@ -42,13 +52,12 @@ function ub64(buffer) {
* @param {String} message The message to send
* @param {Object} subscription The subscription details for the client we
* are sending to
* @param {String} authToken Optional token to be used in the
* `Authentication` header if the endpoint
* requires it.
* @param {Number} paddingLength The number of bytes of padding to add to the
* message before encrypting it.
* @return {Promise} A promise that resolves if the push was sent successfully
* with status and body.
*/
function sendWebPush(message, subscription, authToken) {
function sendWebPush(message, subscription, paddingLength) {
if (!subscription || !subscription.endpoint) {
throw new Error('sendWebPush() expects a subscription endpoint with ' +
'an endpoint parameter.');
Expand All @@ -58,23 +67,31 @@ function sendWebPush(message, subscription, authToken) {
// GCM servers support the Web Push protocol. This should go away in the
// future.
const endpoint = subscription.endpoint.replace(GCM_URL, TEMP_GCM_URL);

const payload = encrypt(message, subscription);
const headers = {
'Content-Encoding': 'aesgcm',
'Encryption': `salt=${ub64(payload.salt)}`,
'Crypto-Key': `dh=${ub64(payload.serverPublicKey)}`
// TODO: Make TTL variable
TTL: '0'
};
let body;

if (message && message.length > 0) {
const payload = encrypt(message, subscription, paddingLength);
headers['Content-Encoding'] = 'aesgcm';
headers.Encryption = `salt=${ub64(payload.salt)}`;
headers['Crypto-Key'] = `dh=${ub64(payload.serverPublicKey)}`;
body = payload.ciphertext;
}

if (authToken) {
headers.Authorization = `key=${authToken}`;
} else if (endpoint.indexOf(TEMP_GCM_URL) !== -1) {
throw new Error('GCM requires an Auth Token parameter');
if (endpoint.indexOf(TEMP_GCM_URL) !== -1) {
if (gcmAuthToken) {
headers.Authorization = `key=${gcmAuthToken}`;
} else {
throw new Error('GCM requires an Auth Token parameter');
}
}

return new Promise(function(resolve, reject) {
request.post(endpoint, {
body: payload.ciphertext,
body: body,
headers: headers
}, function(error, response, body) {
if (error) {
Expand All @@ -101,4 +118,4 @@ function sendWebPush(message, subscription, authToken) {
});
}

module.exports = sendWebPush;
module.exports = {sendWebPush, setGCMAPIKey};
5 changes: 3 additions & 2 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ describe('Test the Libraries Top Level API', function() {
const library = proxyquire('../src/index.js', {
'./push': pushProxy
});
return library.sendWebPush('Hello, World!', VALID_SUBSCRIPTION)
return library.sendWebPush(new Buffer('Hello, World!', 'utf8'), VALID_SUBSCRIPTION)
.then(response => {
response.statusCode.should.equal(200);
response.statusMessage.should.equal('Status message');
Expand Down Expand Up @@ -338,7 +338,8 @@ describe('Test the Libraries Top Level API', function() {
const library = proxyquire('../src/index.js', {
'./push': pushProxy
});
return library.sendWebPush('Hello, World!', gcmSubscription, API_KEY)
library.setGCMAPIKey(API_KEY);
return library.sendWebPush('Hello, World!', gcmSubscription)
.then(response => {
response.statusCode.should.equal(200);
response.statusMessage.should.equal('Status message');
Expand Down