Convert all push recipes to use VAPID

This commit is contained in:
Sebastiaan Lokhorst 2018-03-04 16:23:28 +01:00
Родитель 896b9cc377
Коммит fdf0806969
35 изменённых файлов: 506 добавлений и 414 удалений

Просмотреть файл

@ -11,8 +11,6 @@
white-space: pre-wrap;
}
</style>
<!-- This is needed for Google Chrome support. -->
<link rel="manifest" href="manifest.webmanifest">
</head>
<body>
<p>This demo shows how to control the clients of a service worker when the user clicks on a push notification.</p>
@ -26,6 +24,7 @@
<button id="doIt">Send notification</button>
<script src="/tools.js"></script>
<script src="./index.js"></script>
</body>
</html>

Просмотреть файл

@ -1,23 +1,29 @@
var endpoint;
// Register a Service Worker.
navigator.serviceWorker.register('service-worker.js')
.then(function(registration) {
// Use the PushManager to get the user's subscription to the push service.
return registration.pushManager.getSubscription()
.then(function(subscription) {
.then(async function(subscription) {
// If a subscription was found, return it.
if (subscription) {
return subscription;
}
// Get the server's public key
const response = await fetch('./vapidPublicKey');
const vapidPublicKey = await response.text();
// Chrome doesn't accept the base64-encoded (string) vapidPublicKey yet
// urlBase64ToUint8Array() is defined in /tools.js
const convertedVapidKey = urlBase64ToUint8Array(vapidPublicKey);
// Otherwise, subscribe the user (userVisibleOnly allows to specify that we don't plan to
// send notifications that don't have a visible effect for the user).
return registration.pushManager.subscribe({ userVisibleOnly: true });
return registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: convertedVapidKey
});
});
}).then(function(subscription) {
endpoint = subscription.endpoint;
// Send the subscription details to the server using the Fetch API.
fetch('./register', {
method: 'post',
@ -25,15 +31,23 @@ navigator.serviceWorker.register('service-worker.js')
'Content-type': 'application/json'
},
body: JSON.stringify({
endpoint: subscription.endpoint,
subscription: subscription
}),
});
});
// Ask the server to send the client a notification (for testing purposes, in real
// applications the notification will be generated by some event on the server).
document.getElementById('doIt').addEventListener('click', function() {
fetch('./sendNotification?endpoint=' + endpoint, {
method: 'post',
});
document.getElementById('doIt').onclick = function() {
// Ask the server to send the client a notification (for testing purposes, in actual
// applications the push notification is likely going to be generated by some event
// in the server).
fetch('./sendNotification', {
method: 'post',
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify({
subscription: subscription
}),
});
};
});

Просмотреть файл

@ -1,8 +0,0 @@
{
"name": "Push Clients - Service Worker Cookbook",
"short_name": "push-clients",
"start_url": "./index.html",
"display": "standalone",
"gcm_sender_id": "829371921996",
"gcm_user_visible_only": true
}

Просмотреть файл

@ -2,22 +2,40 @@
// between the application server and the push service.
// For details, see https://tools.ietf.org/html/draft-ietf-webpush-protocol and
// https://tools.ietf.org/html/draft-ietf-webpush-encryption.
var webPush = require('web-push');
const webPush = require('web-push');
webPush.setGCMAPIKey(process.env.GCM_API_KEY || null);
if (!process.env.VAPID_PUBLIC_KEY || !process.env.VAPID_PRIVATE_KEY) {
console.log("You must set the VAPID_PUBLIC_KEY and VAPID_PRIVATE_KEY "+
"environment variables. You can use the following ones:");
console.log(webPush.generateVAPIDKeys());
return;
}
// Set the keys used for encrypting the push messages.
webPush.setVapidDetails(
'https://serviceworke.rs/',
process.env.VAPID_PUBLIC_KEY,
process.env.VAPID_PRIVATE_KEY,
);
module.exports = function(app, route) {
app.get(route + 'vapidPublicKey', function(req, res) {
res.send(process.env.VAPID_PUBLIC_KEY);
});
app.post(route + 'register', function(req, res) {
// A real world application would store the subscription info.
res.sendStatus(201);
});
app.post(route + 'sendNotification', function(req, res) {
const subscription = req.body.subscription;
const payload = null;
const options = {
TTL: req.body.ttl
};
setTimeout(function() {
webPush.sendNotification({
endpoint: req.query.endpoint,
TTL: req.query.ttl,
})
webPush.sendNotification(subscription, payload, options)
.then(function() {
res.sendStatus(201);
})

Просмотреть файл

@ -6,7 +6,7 @@ Send push notifications and retrieve a payload once a notification is received.
Beginner
## Use Case
This recipe demonstrates how you can deliver a notification and retrieve a payload when it arrives, also for browsers that don't currently support push messages with payload.
This recipe demonstrates how you can deliver a notification and retrieve a payload when it arrives.
## Category
Web Push

Просмотреть файл

@ -11,8 +11,6 @@
white-space: pre-wrap;
}
</style>
<!-- This is needed for Google Chrome support. -->
<link rel="manifest" href="manifest.webmanifest">
</head>
<body>
<p>This demo shows how to send push notifications and retrieve a payload when the notification is received.</p>
@ -25,6 +23,7 @@ Notification Time-To-Live: <input id='notification-ttl' type='number' value='0'>
<button id="doIt">Request sending a notification!</button>
<script src="/tools.js"></script>
<script src="./index.js"></script>
</body>
</html>

Просмотреть файл

@ -1,23 +1,29 @@
var endpoint;
// Register a Service Worker.
navigator.serviceWorker.register('service-worker.js')
.then(function(registration) {
// Use the PushManager to get the user's subscription to the push service.
return registration.pushManager.getSubscription()
.then(function(subscription) {
.then(async function(subscription) {
// If a subscription was found, return it.
if (subscription) {
return subscription;
}
// Get the server's public key
const response = await fetch('./vapidPublicKey');
const vapidPublicKey = await response.text();
// Chrome doesn't accept the base64-encoded (string) vapidPublicKey yet
// urlBase64ToUint8Array() is defined in /tools.js
const convertedVapidKey = urlBase64ToUint8Array(vapidPublicKey);
// Otherwise, subscribe the user (userVisibleOnly allows to specify that we don't plan to
// send notifications that don't have a visible effect for the user).
return registration.pushManager.subscribe({ userVisibleOnly: true });
return registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: convertedVapidKey
});
});
}).then(function(subscription) {
endpoint = subscription.endpoint;
// Send the subscription details to the server using the Fetch API.
fetch('./register', {
method: 'post',
@ -25,29 +31,30 @@ navigator.serviceWorker.register('service-worker.js')
'Content-type': 'application/json'
},
body: JSON.stringify({
endpoint: subscription.endpoint,
subscription: subscription
}),
});
document.getElementById('doIt').onclick = function() {
const payload = document.getElementById('notification-payload').value;
const delay = document.getElementById('notification-delay').value;
const ttl = document.getElementById('notification-ttl').value;
// Ask the server to send the client a notification (for testing purposes, in actual
// applications the push notification is likely going to be generated by some event
// in the server).
fetch('./sendNotification', {
method: 'post',
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify({
subscription: subscription,
payload: payload,
delay: delay,
ttl: ttl,
}),
});
};
});
document.getElementById('doIt').onclick = function() {
var payload = document.getElementById('notification-payload').value;
var delay = document.getElementById('notification-delay').value;
var ttl = document.getElementById('notification-ttl').value;
// Ask the server to send the client a notification (for testing purposes, in actual
// applications the push notification is likely going to be generated by some event
// in the server).
fetch('./sendNotification', {
method: 'post',
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify({
endpoint: endpoint,
payload: payload,
delay: delay,
ttl: ttl,
}),
});
};

Просмотреть файл

@ -1,8 +0,0 @@
{
"name": "Push Payload - Service Worker Cookbook",
"short_name": "push-get-payload",
"start_url": "./index.html",
"display": "standalone",
"gcm_sender_id": "829371921996",
"gcm_user_visible_only": true
}

Просмотреть файл

@ -2,25 +2,43 @@
// between the application server and the push service.
// For details, see https://tools.ietf.org/html/draft-ietf-webpush-protocol and
// https://tools.ietf.org/html/draft-ietf-webpush-encryption.
var webPush = require('web-push');
const webPush = require('web-push');
webPush.setGCMAPIKey(process.env.GCM_API_KEY || null);
if (!process.env.VAPID_PUBLIC_KEY || !process.env.VAPID_PRIVATE_KEY) {
console.log("You must set the VAPID_PUBLIC_KEY and VAPID_PRIVATE_KEY "+
"environment variables. You can use the following ones:");
console.log(webPush.generateVAPIDKeys());
return;
}
// Set the keys used for encrypting the push messages.
webPush.setVapidDetails(
'https://serviceworke.rs/',
process.env.VAPID_PUBLIC_KEY,
process.env.VAPID_PRIVATE_KEY,
);
var payloads = {};
const payloads = {};
module.exports = function(app, route) {
app.get(route + 'vapidPublicKey', function(req, res) {
res.send(process.env.VAPID_PUBLIC_KEY);
});
app.post(route + 'register', function(req, res) {
// A real world application would store the subscription info.
res.sendStatus(201);
});
app.post(route + 'sendNotification', function(req, res) {
const subscription = req.body.subscription;
const payload = req.body.payload;
const options = {
TTL: req.body.ttl
};
setTimeout(function() {
payloads[req.body.endpoint] = req.body.payload;
webPush.sendNotification({
endpoint: req.body.endpoint,
TTL: req.body.ttl,
})
payloads[req.body.endpoint] = payload;
webPush.sendNotification(subscription, null, options)
.then(function() {
res.sendStatus(201);
})

Просмотреть файл

@ -11,8 +11,6 @@
white-space: pre-wrap;
}
</style>
<!-- This is needed for Google Chrome support. -->
<link rel="manifest" href="manifest.webmanifest">
</head>
<body>
<p>This demo shows how to send push notifications with a payload.</p>
@ -25,6 +23,7 @@ Notification Time-To-Live: <input id='notification-ttl' type='number' value='0'>
<button id="doIt">Request sending a notification!</button>
<script src="/tools.js"></script>
<script src="./index.js"></script>
</body>
</html>

Просмотреть файл

@ -1,35 +1,29 @@
var endpoint;
var key;
var authSecret;
// Register a Service Worker.
navigator.serviceWorker.register('service-worker.js')
.then(function(registration) {
// Use the PushManager to get the user's subscription to the push service.
return registration.pushManager.getSubscription()
.then(function(subscription) {
.then(async function(subscription) {
// If a subscription was found, return it.
if (subscription) {
return subscription;
}
// Get the server's public key
const response = await fetch('./vapidPublicKey');
const vapidPublicKey = await response.text();
// Chrome doesn't accept the base64-encoded (string) vapidPublicKey yet
// urlBase64ToUint8Array() is defined in /tools.js
const convertedVapidKey = urlBase64ToUint8Array(vapidPublicKey);
// Otherwise, subscribe the user (userVisibleOnly allows to specify that we don't plan to
// send notifications that don't have a visible effect for the user).
return registration.pushManager.subscribe({ userVisibleOnly: true });
return registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: convertedVapidKey
});
});
}).then(function(subscription) {
// Retrieve the user's public key.
var rawKey = subscription.getKey ? subscription.getKey('p256dh') : '';
key = rawKey ?
btoa(String.fromCharCode.apply(null, new Uint8Array(rawKey))) :
'';
var rawAuthSecret = subscription.getKey ? subscription.getKey('auth') : '';
authSecret = rawAuthSecret ?
btoa(String.fromCharCode.apply(null, new Uint8Array(rawAuthSecret))) :
'';
endpoint = subscription.endpoint;
// Send the subscription details to the server using the Fetch API.
fetch('./register', {
method: 'post',
@ -37,33 +31,30 @@ navigator.serviceWorker.register('service-worker.js')
'Content-type': 'application/json'
},
body: JSON.stringify({
endpoint: subscription.endpoint,
key: key,
authSecret: authSecret,
subscription: subscription
}),
});
document.getElementById('doIt').onclick = function() {
const payload = document.getElementById('notification-payload').value;
const delay = document.getElementById('notification-delay').value;
const ttl = document.getElementById('notification-ttl').value;
// Ask the server to send the client a notification (for testing purposes, in actual
// applications the push notification is likely going to be generated by some event
// in the server).
fetch('./sendNotification', {
method: 'post',
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify({
subscription: subscription,
payload: payload,
delay: delay,
ttl: ttl,
}),
});
};
});
document.getElementById('doIt').onclick = function() {
var payload = document.getElementById('notification-payload').value;
var delay = document.getElementById('notification-delay').value;
var ttl = document.getElementById('notification-ttl').value;
// Ask the server to send the client a notification (for testing purposes, in actual
// applications the push notification is likely going to be generated by some event
// in the server).
fetch('./sendNotification', {
method: 'post',
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify({
endpoint: endpoint,
key: key,
authSecret: authSecret,
payload: payload,
delay: delay,
ttl: ttl,
}),
});
};

Просмотреть файл

@ -1,8 +0,0 @@
{
"name": "Push Payload - Service Worker Cookbook",
"short_name": "push-payload",
"start_url": "./index.html",
"display": "standalone",
"gcm_sender_id": "829371921996",
"gcm_user_visible_only": true
}

Просмотреть файл

@ -2,26 +2,40 @@
// between the application server and the push service.
// For details, see https://tools.ietf.org/html/draft-ietf-webpush-protocol and
// https://tools.ietf.org/html/draft-ietf-webpush-encryption.
var webPush = require('web-push');
const webPush = require('web-push');
webPush.setGCMAPIKey(process.env.GCM_API_KEY || null);
if (!process.env.VAPID_PUBLIC_KEY || !process.env.VAPID_PRIVATE_KEY) {
console.log("You must set the VAPID_PUBLIC_KEY and VAPID_PRIVATE_KEY "+
"environment variables. You can use the following ones:");
console.log(webPush.generateVAPIDKeys());
return;
}
// Set the keys used for encrypting the push messages.
webPush.setVapidDetails(
'https://serviceworke.rs/',
process.env.VAPID_PUBLIC_KEY,
process.env.VAPID_PRIVATE_KEY,
);
module.exports = function(app, route) {
app.get(route + 'vapidPublicKey', function(req, res) {
res.send(process.env.VAPID_PUBLIC_KEY);
});
app.post(route + 'register', function(req, res) {
// A real world application would store the subscription info.
res.sendStatus(201);
});
app.post(route + 'sendNotification', function(req, res) {
const subscription = req.body.subscription;
const payload = req.body.payload;
const options = {
TTL: req.body.ttl
};
setTimeout(function() {
webPush.sendNotification({
endpoint: req.body.endpoint,
TTL: req.body.ttl,
keys: {
p256dh: req.body.key,
auth: req.body.authSecret
}
}, req.body.payload)
webPush.sendNotification(subscription, payload, options)
.then(function() {
res.sendStatus(201);
})

Просмотреть файл

@ -3,7 +3,7 @@ self.addEventListener('push', function(event) {
// Retrieve the textual payload from event.data (a PushMessageData object).
// Other formats are supported (ArrayBuffer, Blob, JSON), check out the documentation
// on https://developer.mozilla.org/en-US/docs/Web/API/PushMessageData.
var payload = event.data ? event.data.text() : 'no payload';
const payload = event.data ? event.data.text() : 'no payload';
// Keep the service worker alive until the notification is created.
event.waitUntil(

Просмотреть файл

@ -15,8 +15,6 @@
color: red;
}
</style>
<!-- This is needed for Google Chrome support. -->
<link rel="manifest" href="manifest.webmanifest">
</head>
<body>
<p>This demo allows you to experiment with the quota management rules enforced by browsers.
@ -39,6 +37,7 @@ Number of notifications to send: <input id="notification-num" type="number" valu
Received <span id="sent-invisible">0</span> invisible notifications</p>
<button id="clear">Clear</button>
<script src="/tools.js"></script>
<script src="./index.js"></script>
</body>
</html>

Просмотреть файл

@ -1,36 +1,29 @@
var endpoint;
var key;
var authSecret;
// Register a Service Worker.
navigator.serviceWorker.register('service-worker.js')
.then(function(registration) {
// Use the PushManager to get the user's subscription to the push service.
return registration.pushManager.getSubscription()
.then(function(subscription) {
.then(async function(subscription) {
// If a subscription was found, return it.
if (subscription) {
return subscription;
}
// Get the server's public key
const response = await fetch('./vapidPublicKey');
const vapidPublicKey = await response.text();
// Chrome doesn't accept the base64-encoded (string) vapidPublicKey yet
// urlBase64ToUint8Array() is defined in /tools.js
const convertedVapidKey = urlBase64ToUint8Array(vapidPublicKey);
// Otherwise, subscribe the user (unlike the other push recipes, here we don't set
// the userVisibleOnly property because we don't plan to only send notifications that
// have a visible effect for the user).
return registration.pushManager.subscribe();
return registration.pushManager.subscribe({
applicationServerKey: convertedVapidKey
});
});
}).then(function(subscription) {
// Retrieve the user's public key.
var rawKey = subscription.getKey ? subscription.getKey('p256dh') : '';
key = rawKey ?
btoa(String.fromCharCode.apply(null, new Uint8Array(rawKey))) :
'';
var rawAuthSecret = subscription.getKey ? subscription.getKey('auth') : '';
authSecret = rawAuthSecret ?
btoa(String.fromCharCode.apply(null, new Uint8Array(rawAuthSecret))) :
'';
endpoint = subscription.endpoint;
// Send the subscription details to the server using the Fetch API.
fetch('./register', {
method: 'post',
@ -38,65 +31,63 @@ navigator.serviceWorker.register('service-worker.js')
'Content-type': 'application/json'
},
body: JSON.stringify({
endpoint: subscription.endpoint,
key: key,
authSecret: authSecret,
subscription: subscription
}),
});
});
function askForNotifications(visible) {
var notificationNum = document.getElementById('notification-num').value;
// Ask the server to send the client a notification (for testing purposes, in real
// applications the notification will be generated by some event on the server).
fetch('./sendNotification', {
method: 'post',
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify({
endpoint: endpoint,
key: key,
authSecret: authSecret,
visible: visible,
num: notificationNum,
}),
});
}
function askForNotifications(visible) {
var notificationNum = document.getElementById('notification-num').value;
document.getElementById('visible').onclick = function() {
// Ask the server to send a notification, that the service worker will then use
// to show a visible notification.
askForNotifications(true);
};
document.getElementById('invisible').onclick = function() {
// Ask the server to send a notification, that the service worker will not use
// to show a visible notification.
askForNotifications(false);
};
document.getElementById('clear').onclick = function() {
// Clear the 'notifications' cache, that stores the number of visible/invisible
// notifications received.
window.caches.open('notifications').then(function(cache) {
Promise.all([
cache.put(new Request('invisible'), new Response('0', {
headers: {
'content-type': 'application/json'
}
})),
cache.put(new Request('visible'), new Response('0', {
headers: {
'content-type': 'application/json'
}
})),
]).then(function() {
updateNumbers();
// Ask the server to send the client a notification (for testing purposes, in real
// applications the notification will be generated by some event on the server).
fetch('./sendNotification', {
method: 'post',
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify({
subscription: subscription,
visible: visible,
num: notificationNum,
}),
});
});
};
}
document.getElementById('visible').onclick = function() {
// Ask the server to send a notification, that the service worker will then use
// to show a visible notification.
askForNotifications(true);
};
document.getElementById('invisible').onclick = function() {
// Ask the server to send a notification, that the service worker will not use
// to show a visible notification.
askForNotifications(false);
};
document.getElementById('clear').onclick = function() {
// Clear the 'notifications' cache, that stores the number of visible/invisible
// notifications received.
window.caches.open('notifications').then(function(cache) {
Promise.all([
cache.put(new Request('invisible'), new Response('0', {
headers: {
'content-type': 'application/json'
}
})),
cache.put(new Request('visible'), new Response('0', {
headers: {
'content-type': 'application/json'
}
})),
]).then(function() {
updateNumbers();
});
});
};
});
function updateNumbers() {
// Read the number of notifications received from the 'notifications' cache and

Просмотреть файл

@ -1,8 +0,0 @@
{
"name": "Push Quota - Service Worker Cookbook",
"short_name": "push-quota",
"start_url": "./index.html",
"display": "standalone",
"gcm_sender_id": "829371921996",
"gcm_user_visible_only": true
}

Просмотреть файл

@ -2,11 +2,26 @@
// between the application server and the push service.
// For details, see https://tools.ietf.org/html/draft-ietf-webpush-protocol and
// https://tools.ietf.org/html/draft-ietf-webpush-encryption.
var webPush = require('web-push');
const webPush = require('web-push');
webPush.setGCMAPIKey(process.env.GCM_API_KEY || null);
if (!process.env.VAPID_PUBLIC_KEY || !process.env.VAPID_PRIVATE_KEY) {
console.log("You must set the VAPID_PUBLIC_KEY and VAPID_PRIVATE_KEY "+
"environment variables. You can use the following ones:");
console.log(webPush.generateVAPIDKeys());
return;
}
// Set the keys used for encrypting the push messages.
webPush.setVapidDetails(
'https://serviceworke.rs/',
process.env.VAPID_PUBLIC_KEY,
process.env.VAPID_PRIVATE_KEY,
);
module.exports = function(app, route) {
app.get(route + 'vapidPublicKey', function(req, res) {
res.send(process.env.VAPID_PUBLIC_KEY);
});
app.post(route + 'register', function(req, res) {
// A real world application would store the subscription info.
res.sendStatus(201);
@ -17,19 +32,18 @@ module.exports = function(app, route) {
// - 'true': show a notification;
// - 'false': don't show a notification.
app.post(route + 'sendNotification', function(req, res) {
var num = 1;
const subscription = req.body.subscription;
const payload = null;
const options = {
TTL: 200
};
var promises = [];
let num = 1;
var intervalID = setInterval(function() {
promises.push(webPush.sendNotification({
endpoint: req.body.endpoint,
TTL: 200,
keys: {
p256dh: req.body.key,
auth: req.body.authSecret,
}
}));
let promises = [];
let intervalID = setInterval(function() {
promises.push(webPush.sendNotification(subscription, payload, options));
if (num++ === Number(req.body.num)) {
clearInterval(intervalID);

Просмотреть файл

@ -11,8 +11,6 @@
white-space: pre-wrap;
}
</style>
<!-- This is needed for Google Chrome support. -->
<link rel="manifest" href="manifest.webmanifest">
</head>
<body>
<p>This demo shows how to replace an old notification with a new one.</p>
@ -23,6 +21,7 @@ Delay between notifications: <input id='notification-delay' type='number' value=
<button id="doIt">Request notifications</button>
<script src="/tools.js"></script>
<script src="./index.js"></script>
</body>
</html>

Просмотреть файл

@ -1,23 +1,29 @@
var endpoint;
// Register a Service Worker.
navigator.serviceWorker.register('service-worker.js')
.then(function(registration) {
// Use the PushManager to get the user's subscription to the push service.
return registration.pushManager.getSubscription()
.then(function(subscription) {
.then(async function(subscription) {
// If a subscription was found, return it.
if (subscription) {
return subscription;
}
// Get the server's public key
const response = await fetch('./vapidPublicKey');
const vapidPublicKey = await response.text();
// Chrome doesn't accept the base64-encoded (string) vapidPublicKey yet
// urlBase64ToUint8Array() is defined in /tools.js
const convertedVapidKey = urlBase64ToUint8Array(vapidPublicKey);
// Otherwise, subscribe the user (userVisibleOnly allows to specify that we don't plan to
// send notifications that don't have a visible effect for the user).
return registration.pushManager.subscribe({ userVisibleOnly: true });
return registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: convertedVapidKey
});
});
}).then(function(subscription) {
endpoint = subscription.endpoint;
// Send the subscription details to the server using the Fetch API.
fetch('./register', {
method: 'post',
@ -25,20 +31,26 @@ navigator.serviceWorker.register('service-worker.js')
'Content-type': 'application/json'
},
body: JSON.stringify({
endpoint: subscription.endpoint,
subscription: subscription
}),
});
});
document.getElementById('doIt').onclick = function() {
var notificationDelay = document.getElementById('notification-delay').value;
document.getElementById('doIt').onclick = function() {
const delay = document.getElementById('notification-delay').value;
// Ask the server to send the client a few notifications (for testing purposes, in real
// applications notifications will be generated by events on the server).
fetch('./sendNotification?endpoint=' + endpoint +
'&delay=' + notificationDelay,
{
// Ask the server to send the client a notification (for testing purposes, in actual
// applications the push notification is likely going to be generated by some event
// in the server).
fetch('./sendNotification', {
method: 'post',
}
);
};
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify({
subscription: subscription,
delay: delay,
}),
});
};
});

Просмотреть файл

@ -1,8 +0,0 @@
{
"name": "Push Replace - Service Worker Cookbook",
"short_name": "push-replace",
"start_url": "./index.html",
"display": "standalone",
"gcm_sender_id": "829371921996",
"gcm_user_visible_only": true
}

Просмотреть файл

@ -2,33 +2,48 @@
// between the application server and the push service.
// For details, see https://tools.ietf.org/html/draft-ietf-webpush-protocol and
// https://tools.ietf.org/html/draft-ietf-webpush-encryption.
var webPush = require('web-push');
const webPush = require('web-push');
webPush.setGCMAPIKey(process.env.GCM_API_KEY || null);
if (!process.env.VAPID_PUBLIC_KEY || !process.env.VAPID_PRIVATE_KEY) {
console.log("You must set the VAPID_PUBLIC_KEY and VAPID_PRIVATE_KEY "+
"environment variables. You can use the following ones:");
console.log(webPush.generateVAPIDKeys());
return;
}
// Set the keys used for encrypting the push messages.
webPush.setVapidDetails(
'https://serviceworke.rs/',
process.env.VAPID_PUBLIC_KEY,
process.env.VAPID_PRIVATE_KEY,
);
module.exports = function(app, route) {
app.get(route + 'vapidPublicKey', function(req, res) {
res.send(process.env.VAPID_PUBLIC_KEY);
});
app.post(route + 'register', function(req, res) {
// A real world application would store the subscription info.
res.sendStatus(201);
});
app.post(route + 'sendNotification', function(req, res) {
webPush.sendNotification({
endpoint: req.query.endpoint,
TTL: 200,
})
const subscription = req.body.subscription;
const payload = null;
const options = {
TTL: 200
};
webPush.sendNotification(subscription, payload, options)
.catch(logError);
setTimeout(function() {
webPush.sendNotification({
endpoint: req.query.endpoint,
TTL: 200,
})
webPush.sendNotification(subscription, payload, options)
.then(function() {
res.sendStatus(201);
})
.catch(logError);
}, req.query.delay * 1000);
}, req.body.delay * 1000);
function logError(error) {
res.sendStatus(500);

Просмотреть файл

@ -1,4 +1,4 @@
var num = 1;
let num = 1;
// Register event listener for the 'push' event.
self.addEventListener('push', function(event) {

Просмотреть файл

@ -11,8 +11,6 @@
white-space: pre-wrap;
}
</style>
<!-- This is needed for Google Chrome support. -->
<link rel="manifest" href="manifest.webmanifest">
</head>
<body>
<p>This demo shows how to show rich push notifications.</p>
@ -24,6 +22,7 @@ Notification Time-To-Live: <input id='notification-ttl' type='number' value='0'>
<button id="doIt">Try to conquer Italy!</button>
<script src="/tools.js"></script>
<script src="./index.js"></script>
</body>
</html>

Просмотреть файл

@ -1,23 +1,29 @@
var endpoint;
// Register a Service Worker.
navigator.serviceWorker.register('service-worker.js')
.then(function(registration) {
// Use the PushManager to get the user's subscription to the push service.
return registration.pushManager.getSubscription()
.then(function(subscription) {
.then(async function(subscription) {
// If a subscription was found, return it.
if (subscription) {
return subscription;
}
// Get the server's public key
const response = await fetch('./vapidPublicKey');
const vapidPublicKey = await response.text();
// Chrome doesn't accept the base64-encoded (string) vapidPublicKey yet
// urlBase64ToUint8Array() is defined in /tools.js
const convertedVapidKey = urlBase64ToUint8Array(vapidPublicKey);
// Otherwise, subscribe the user (userVisibleOnly allows to specify that we don't plan to
// send notifications that don't have a visible effect for the user).
return registration.pushManager.subscribe({ userVisibleOnly: true });
return registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: convertedVapidKey
});
});
}).then(function(subscription) {
endpoint = subscription.endpoint;
// Send the subscription details to the server using the Fetch API.
fetch('./register', {
method: 'post',
@ -25,21 +31,28 @@ navigator.serviceWorker.register('service-worker.js')
'Content-type': 'application/json'
},
body: JSON.stringify({
endpoint: subscription.endpoint,
subscription: subscription
}),
});
});
document.getElementById('doIt').onclick = function() {
var delay = document.getElementById('notification-delay').value;
var ttl = document.getElementById('notification-ttl').value;
document.getElementById('doIt').onclick = function() {
const delay = document.getElementById('notification-delay').value;
const ttl = document.getElementById('notification-ttl').value;
// Ask the server to send the client a notification (for testing purposes, in real
// applications the notification will be generated by some event on the server).
fetch('./sendNotification?endpoint=' + endpoint + '&delay=' + delay +
'&ttl=' + ttl,
{
// Ask the server to send the client a notification (for testing purposes, in actual
// applications the push notification is likely going to be generated by some event
// in the server).
fetch('./sendNotification', {
method: 'post',
}
);
};
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify({
subscription: subscription,
delay: delay,
ttl: ttl,
}),
});
};
});

Просмотреть файл

@ -1,8 +0,0 @@
{
"name": "Push Rich - Service Worker Cookbook",
"short_name": "push-rich",
"start_url": "./index.html",
"display": "standalone",
"gcm_sender_id": "829371921996",
"gcm_user_visible_only": true
}

Просмотреть файл

@ -2,29 +2,47 @@
// between the application server and the push service.
// For details, see https://tools.ietf.org/html/draft-ietf-webpush-protocol and
// https://tools.ietf.org/html/draft-ietf-webpush-encryption.
var webPush = require('web-push');
const webPush = require('web-push');
webPush.setGCMAPIKey(process.env.GCM_API_KEY || null);
if (!process.env.VAPID_PUBLIC_KEY || !process.env.VAPID_PRIVATE_KEY) {
console.log("You must set the VAPID_PUBLIC_KEY and VAPID_PRIVATE_KEY "+
"environment variables. You can use the following ones:");
console.log(webPush.generateVAPIDKeys());
return;
}
// Set the keys used for encrypting the push messages.
webPush.setVapidDetails(
'https://serviceworke.rs/',
process.env.VAPID_PUBLIC_KEY,
process.env.VAPID_PRIVATE_KEY,
);
module.exports = function(app, route) {
app.get(route + 'vapidPublicKey', function(req, res) {
res.send(process.env.VAPID_PUBLIC_KEY);
});
app.post(route + 'register', function(req, res) {
// A real world application would store the subscription info.
res.sendStatus(201);
});
app.post(route + 'sendNotification', function(req, res) {
const subscription = req.body.subscription;
const payload = null;
const options = {
TTL: req.body.ttl
};
setTimeout(function() {
webPush.sendNotification({
endpoint: req.query.endpoint,
TTL: req.query.ttl,
})
webPush.sendNotification(subscription, payload, options)
.then(function() {
res.sendStatus(201);
})
.catch(function(error) {
res.sendStatus(500);
console.log(error);
})
}, req.query.delay * 1000);
res.sendStatus(500);
});
}, req.body.delay * 1000);
});
};

Просмотреть файл

@ -10,13 +10,7 @@
font-size: 1rem;
white-space: pre-wrap;
}
span {
font-style: italic;
}
</style>
<!-- This is needed for Google Chrome support. -->
<link rel="manifest" href="manifest.webmanifest">
</head>
<body>
<p>This demo shows how to register for push notifications and how to send them.</p>
@ -26,12 +20,9 @@ Notification delay: <input id='notification-delay' type='number' value='5'></inp
Notification Time-To-Live: <input id='notification-ttl' type='number' value='0'></input> seconds
</form>
<p>Either click this button to ask the server to send a notification: <button id="doIt">Try to conquer Italy!</button></p>
<p>Or use <b>curl</b> on your command line to send the notification:</p>
<span id="curl"></span>
<p>N.B.: The curl command only works for push services implementing the Web Push standard (GCM, the push service used by Google Chrome, currently doesn't).</p>
<button id="doIt">Try to conquer Italy!</button>
<script src="/tools.js"></script>
<script src="./index.js"></script>
</body>
</html>

Просмотреть файл

@ -1,26 +1,29 @@
var endpoint;
// Register a Service Worker.
navigator.serviceWorker.register('service-worker.js')
.then(function(registration) {
// Use the PushManager to get the user's subscription to the push service.
return registration.pushManager.getSubscription()
.then(function(subscription) {
.then(async function(subscription) {
// If a subscription was found, return it.
if (subscription) {
return subscription;
}
// Get the server's public key
const response = await fetch('./vapidPublicKey');
const vapidPublicKey = await response.text();
// Chrome doesn't accept the base64-encoded (string) vapidPublicKey yet
// urlBase64ToUint8Array() is defined in /tools.js
const convertedVapidKey = urlBase64ToUint8Array(vapidPublicKey);
// Otherwise, subscribe the user (userVisibleOnly allows to specify that we don't plan to
// send notifications that don't have a visible effect for the user).
return registration.pushManager.subscribe({ userVisibleOnly: true });
return registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: convertedVapidKey
});
});
}).then(function(subscription) {
endpoint = subscription.endpoint;
// Show curl command to send the notification on the page.
document.getElementById('curl').textContent = 'curl -H "TTL: 60" -X POST ' + endpoint;
// Send the subscription details to the server using the Fetch API.
fetch('./register', {
method: 'post',
@ -28,23 +31,28 @@ navigator.serviceWorker.register('service-worker.js')
'Content-type': 'application/json'
},
body: JSON.stringify({
endpoint: subscription.endpoint,
subscription: subscription
}),
});
});
document.getElementById('doIt').onclick = function() {
var delay = document.getElementById('notification-delay').value;
var ttl = document.getElementById('notification-ttl').value;
document.getElementById('doIt').onclick = function() {
const delay = document.getElementById('notification-delay').value;
const ttl = document.getElementById('notification-ttl').value;
// Ask the server to send the client a notification.
// This is for testing purposes, in a real application the notifications will be
// directly generated by the server without the user asking for it (otherwise, what
// would be the point?).
fetch('./sendNotification?endpoint=' + endpoint + '&delay=' + delay +
'&ttl=' + ttl,
{
// Ask the server to send the client a notification (for testing purposes, in actual
// applications the push notification is likely going to be generated by some event
// in the server).
fetch('./sendNotification', {
method: 'post',
}
);
};
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify({
subscription: subscription,
delay: delay,
ttl: ttl,
}),
});
};
});

Просмотреть файл

@ -1,8 +0,0 @@
{
"name": "Push Simple - Service Worker Cookbook",
"short_name": "push-simple",
"start_url": "./index.html",
"display": "standalone",
"gcm_sender_id": "829371921996",
"gcm_user_visible_only": true
}

Просмотреть файл

@ -2,22 +2,40 @@
// between the application server and the push service.
// For details, see https://tools.ietf.org/html/draft-ietf-webpush-protocol and
// https://tools.ietf.org/html/draft-ietf-webpush-encryption.
var webPush = require('web-push');
const webPush = require('web-push');
webPush.setGCMAPIKey(process.env.GCM_API_KEY || null);
if (!process.env.VAPID_PUBLIC_KEY || !process.env.VAPID_PRIVATE_KEY) {
console.log("You must set the VAPID_PUBLIC_KEY and VAPID_PRIVATE_KEY "+
"environment variables. You can use the following ones:");
console.log(webPush.generateVAPIDKeys());
return;
}
// Set the keys used for encrypting the push messages.
webPush.setVapidDetails(
'https://serviceworke.rs/',
process.env.VAPID_PUBLIC_KEY,
process.env.VAPID_PRIVATE_KEY,
);
module.exports = function(app, route) {
app.get(route + 'vapidPublicKey', function(req, res) {
res.send(process.env.VAPID_PUBLIC_KEY);
});
app.post(route + 'register', function(req, res) {
// A real world application would store the subscription info.
res.sendStatus(201);
});
app.post(route + 'sendNotification', function(req, res) {
const subscription = req.body.subscription;
const payload = null;
const options = {
TTL: req.body.ttl
};
setTimeout(function() {
webPush.sendNotification({
endpoint: req.query.endpoint,
TTL: req.query.ttl,
})
webPush.sendNotification(subscription, payload, options)
.then(function() {
res.sendStatus(201);
})
@ -25,6 +43,6 @@ module.exports = function(app, route) {
res.sendStatus(500);
console.log(error);
});
}, req.query.delay * 1000);
}, req.body.delay * 1000);
});
};

Просмотреть файл

@ -11,14 +11,12 @@
white-space: pre-wrap;
}
</style>
<!-- This is needed for Google Chrome support. -->
<link rel="manifest" href="manifest.webmanifest">
</head>
<body>
<p>This demo shows how to subscribe/unsubscribe to the push notifications.</p>
<button id='subscriptionButton' disabled=true></button>
<p>To simulate the subscription expiration under Firefox please set the <code>dom.push.userAgentId</code> in about:config to an empty string. (Note: <A href="https://bugzilla.mozilla.org/show_bug.cgi?id=1222428">bug 1222428</a>)</p>
<script src='./index.js'></script>
<script src="/tools.js"></script>
<script src="./index.js"></script>
</body>
</html>

Просмотреть файл

@ -32,11 +32,21 @@ if ('serviceWorker' in navigator) {
// Get the `registration` from service worker and create a new
// subscription using `registration.pushManager.subscribe`. Then
// register received new subscription by sending a POST request with its
// endpoint to the server.
// register received new subscription by sending a POST request with
// the subscription to the server.
function subscribe() {
navigator.serviceWorker.ready.then(function(registration) {
return registration.pushManager.subscribe({ userVisibleOnly: true });
navigator.serviceWorker.ready.then(async function(registration) {
// Get the server's public key
const response = await fetch('./vapidPublicKey');
const vapidPublicKey = await response.text();
// Chrome doesn't accept the base64-encoded (string) vapidPublicKey yet
// urlBase64ToUint8Array() is defined in /tools.js
const convertedVapidKey = urlBase64ToUint8Array(vapidPublicKey);
// Subscribe the user
return registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: convertedVapidKey
});
}).then(function(subscription) {
console.log('Subscribed', subscription.endpoint);
return fetch('register', {
@ -45,7 +55,7 @@ function subscribe() {
'Content-type': 'application/json'
},
body: JSON.stringify({
endpoint: subscription.endpoint
subscription: subscription
})
});
}).then(setUnsubscribeButton);
@ -66,7 +76,7 @@ function unsubscribe() {
'Content-type': 'application/json'
},
body: JSON.stringify({
endpoint: subscription.endpoint
subscription: subscription
})
});
});

Просмотреть файл

@ -1,8 +0,0 @@
{
"name": "RECIPE: Push notifications with subscription management",
"short_name": "recipe_push_with_subscription",
"start_url": "/index.html",
"display": "standalone",
"gcm_sender_id": "829371921996",
"gcm_user_visible_only": true
}

Просмотреть файл

@ -1,29 +1,42 @@
// [Working example](/serviceworker-cookbook/push-subscription-management/).
// `web-push` is a library which makes sending notifications a very
// simple process.
var webPush = require('web-push');
// Use the web-push library to hide the implementation details of the communication
// between the application server and the push service.
// For details, see https://tools.ietf.org/html/draft-ietf-webpush-protocol and
// https://tools.ietf.org/html/draft-ietf-webpush-encryption.
const webPush = require('web-push');
if (!process.env.VAPID_PUBLIC_KEY || !process.env.VAPID_PRIVATE_KEY) {
console.log("You must set the VAPID_PUBLIC_KEY and VAPID_PRIVATE_KEY "+
"environment variables. You can use the following ones:");
console.log(webPush.generateVAPIDKeys());
return;
}
// Set the keys used for encrypting the push messages.
webPush.setVapidDetails(
'https://serviceworke.rs/',
process.env.VAPID_PUBLIC_KEY,
process.env.VAPID_PRIVATE_KEY,
);
// Global array collecting all active endpoints. In real world
// application one would use a database here.
var subscriptions = [];
const subscriptions = {};
// How often (in seconds) should the server send a notification to the
// user.
var pushInterval = 10;
const pushInterval = 10;
webPush.setGCMAPIKey(process.env.GCM_API_KEY || null);
// Send notification to the push service. Remove the endpoint from the
// Send notification to the push service. Remove the subscription from the
// `subscriptions` array if the push service responds with an error.
// Subscription has been cancelled or expired.
function sendNotification(endpoint) {
webPush.sendNotification({
endpoint: endpoint
}).then(function() {
console.log('Push Application Server - Notification sent to ' + endpoint);
function sendNotification(subscription) {
webPush.sendNotification(subscription)
.then(function() {
console.log('Push Application Server - Notification sent to ' + subscription.endpoint);
}).catch(function() {
console.log('ERROR in sending Notification, endpoint removed ' + endpoint);
subscriptions.splice(subscriptions.indexOf(endpoint), 1);
console.log('ERROR in sending Notification, endpoint removed ' + subscription.endpoint);
delete subscriptions[subscription.endpoint];
});
}
@ -31,31 +44,30 @@ function sendNotification(endpoint) {
// To simulate it, server is sending a notification every `pushInterval` seconds
// to each registered endpoint.
setInterval(function() {
subscriptions.forEach(sendNotification);
Object.values(subscriptions).forEach(sendNotification);
}, pushInterval * 1000);
function isSubscribed(endpoint) {
return (subscriptions.indexOf(endpoint) >= 0);
}
module.exports = function(app, route) {
// Register a subscription by adding an endpoint to the `subscriptions`
// array.
app.get(route + 'vapidPublicKey', function(req, res) {
res.send(process.env.VAPID_PUBLIC_KEY);
});
// Register a subscription by adding it to the `subscriptions` array.
app.post(route + 'register', function(req, res) {
var endpoint = req.body.endpoint;
if (!isSubscribed(endpoint)) {
console.log('Subscription registered ' + endpoint);
subscriptions.push(endpoint);
var subscription = req.body.subscription;
if (!subscriptions[subscription.endpoint]) {
console.log('Subscription registered ' + subscription.endpoint);
subscriptions[subscription.endpoint] = subscription;
}
res.type('js').send('{"success":true}');
});
// Unregister a subscription by removing it from the `subscriptions` array
app.post(route + 'unregister', function(req, res) {
var endpoint = req.body.endpoint;
if (isSubscribed(endpoint)) {
console.log('Subscription unregistered ' + endpoint);
subscriptions.splice(subscriptions.indexOf(endpoint), 1);
var subscription = req.body.subscription;
if (subscriptions[subscription.endpoint]) {
console.log('Subscription unregistered ' + subscription.endpoint);
delete subscriptions[subscription.endpoint];
}
res.type('js').send('{"success":true}');
});