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

Some basic docs to get started with #2

Merged
merged 2 commits into from
Mar 31, 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
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,43 @@ This library provides the functions necessary to encrypt a payload for sending
with the Web Push protocol. It also includes a helper function for actually
send the message to the Web Push endpoint.

What is this for?
-----------------

The [Push API](http://w3c.github.io/push-api/) allow users to subscribe for
notifications from a web site, which can be delivered to them even if the
browser has been closed. This was first shipped as part of Chrome 42, but the
push message could not contain any payload data.

As of Chrome 50 and Firefox 44 (desktop-only) payloads are supported, but the
server must encrypt the payload or the receiving browser will reject it.

This library implements the necessary encryption as a Node module.

Overview
--------

Install the module using npm:

`npm install web-push-encryption`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the name we are actually published on? Does it make sense to make it slightly more generic if we can support encrypted push and just tickles?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted web-push but Mozilla got there first :)

Will open an issue.


Require the module:

`var webpush = require('web-push-encryption');`

Send a message:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seriously, that's all I need to do, I don't need to create any keys, certificates, sign anything, jump on one leg three times while patting my head? If so, I <3 this.


`webpush.sendWebPush('Yay! Web Push!', subscription);`

If the push service requires an authentication header (notably Google Cloud
Messaging, used by Chrome) then you can add that as a third parameter:

```
if (subscription.endpoint.indexOf('https://android.googleapis.com/gcm/send/') === 0) {
webpush.sendWebPush('A message for Chrome', subscription, MY_GCM_KEY);
}
```

Support
-------

Expand Down
3 changes: 1 addition & 2 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,5 @@ const push = require('./push');
// Exports the public API
module.exports = {
encrypt: encrypt,
sendWebPush: push.sendWebPush,
addAuthToken: push.addAuthToken
sendWebPush: push.sendWebPush
};
58 changes: 9 additions & 49 deletions src/push.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,68 +33,31 @@ function ub64(buffer) {
.replace(/\=/g, '');
}

/**
* A helper for creating the value part of the HTTP encryption headers
* @param {String} name The name of the header field
* @param {Buffer} value The value of the field
* @return {String} String representation of the header
*/
function createHeaderField(name, value) {
return `${name}=${ub64(value)}`;
}

const authTokens = [];

/**
* Returns the appropriate authentication token, if any, for the endpoint we are
* trying to send to.
* @param {String} endpoint URL of the endpoint
* @return {String} The authentication token
*/
function getAuthToken(endpoint) {
for (let i = 0; i < authTokens.length; i++) {
if (endpoint.indexOf(authTokens[i].pattern) !== -1) {
return authTokens[i].token;
}
}
}

/**
* Adds a new authentication token. The pattern is a simple string. An endpoint
* will use the given authentication token if the pattern is a substring of the
* endpoint.
* @param {String} pattern The pattern to match on
* @param {String} token The authentication token
*/
function addAuthToken(pattern, token) {
authTokens.push({pattern, token});
}

/**
* Sends a message using the Web Push protocol
* @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.
* @return {Promise} A promise that resolves if the push was sent successfully
* with status and body.
*/
function sendWebPush(message, subscription) {
let endpoint = subscription.endpoint;
const authToken = getAuthToken(endpoint);

function sendWebPush(message, subscription, authToken) {
// If the endpoint is GCM then we temporarily need to rewrite it, as not all
// GCM servers support the Web Push protocol. This should go away in the
// future.
endpoint = endpoint.replace(GCM_URL, TEMP_GCM_URL);
const endpoint = subscription.endpoint.replace(GCM_URL, TEMP_GCM_URL);

const payload = encrypt(message, subscription);
const headers = {
'Encryption': createHeaderField('salt', payload.salt),
'Crypto-Key': createHeaderField('dh', payload.serverPublicKey)
'Encryption': `salt=${ub64(payload.salt)}`,
'Crypto-Key': `dh=${ub64(payload.serverPublicKey)}`
};

if (authToken) {
headers.Authorization = 'key=' + authToken;
headers.Authorization = `key=${authToken}`;
}

return new Promise(function(resolve, reject) {
Expand All @@ -114,7 +77,4 @@ function sendWebPush(message, subscription) {
});
}

module.exports = {
sendWebPush,
addAuthToken
};
module.exports = {sendWebPush};