Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sending data / payload to the Google Chrome Push Notification with Javascript

Tags:

I'm working on the Google Chrome Push Notification and I'm trying to send the payload to the google chrome worker but, I have no idea how I receive this payload.

I have an API to create and save the notifications in my database and I need send the values through the https://android.googleapis.com/gcm/send and receive on the worker.js

This is my worker.js

    self.addEventListener('push', function(event) {       var title = 'Yay a message.';       var body = 'We have received a push message.';       var icon = '/images/icon-192x192.png';       var tag = 'simple-push-demo-notification-tag';        event.waitUntil(         self.registration.showNotification(title, {           body: body,           icon: icon,           tag: tag         })       );     }); 

And this is how I'm calling the GCM

curl --header "Authorization: key=AIzaSyDQjYDxeS9MM0LcJm3oR6B7MU7Ad2x2Vqc" --header  "Content-Type: application/json" https://android.googleapis.com/gcm/send -d "{ \"data\":{\"foo\":\"bar\"}, \"registration_ids\":[\"APA91bGqJpCmyCnSHLjY6STaBQEumz3eFY9r-2CHTtbsUMzBttq0crU3nEXzzU9TxNpsYeFmjA27urSaszKtA0WWC3yez1hhneLjbwJqlRdc_Yj1EiqLHluVwHB6V4FNdXdKb_gc_-7rbkYkypI3MtHpEaJbWsj6M5Pgs4nKqQ2R-WNho82mnRU\"]}" 

I tried to get event.data but, this is undefined.

Does anyone have any idea or sugestion?

like image 929
Adriano Tadao Avatar asked May 19 '15 20:05

Adriano Tadao


People also ask

What is payload in notification?

Each notification your provider server sends to the Apple Push Notification service (APNs) includes a payload. The payload contains any custom data that you want to send to your app and includes information about how the system should notify the user.

Can Google Read push notifications?

Hear a notificationGoogle Assistant will read any notifications that you have.

What is Javascript push notification?

The Web push notification is a protocol that implies 4 actors: the User: that wants to receive the notifications. the Application: that runs on the user-agent (typically the browser) the Service worker: that runs on the browser. the Push Server: that sends push messages to the service worker.


2 Answers

Unfortunately it seems like an intended behavior:

A downside to the current implementation of the Push API in Chrome is that you can’t send a payload with a push message. Nope, nothing. The reason for this is that in a future implementation, payload will have to be encrypted on your server before it’s sent to a push messaging endpoint. This way the endpoint, whatever push provider it is, will not be able to easily view the content of the push payload. This also protects against other vulnerabilities like poor validation of HTTPS certificates and man-in-the-middle attacks between your server and the push provider. However, this encryption isn’t supported yet, so in the meantime you’ll need to perform a fetch request to get information needed to populate a notification.

As stated above, the workaround is to contact back your backend after receiving the push and fetch the stored data on the 3rd party server.

like image 175
gauchofunky Avatar answered Oct 02 '22 13:10

gauchofunky


@gauchofunky's answer is correct. With some guidance from the folks on the Chromium dev slack channel and @gauchofunky I was able to piece something together. Here's how to work around the current limitations; hopefully my answer becomes obsolete soon!

First figure out how you're going to persist notifications on your backend. I'm using Node/Express and MongoDB with Mongoose and my schema looks like this:

var NotificationSchema = new Schema({   _user: {type: mongoose.Schema.Types.ObjectId, ref: 'User'},   subscriptionId: String,   title: String,   body: String,   sent: { type: Boolean, default: false } }); 

Be sure to add an icon if you'd like to alter the icon. I use the same icon every time so mine's hardcoded in the service worker.

Figuring out the correct REST web service took some thought. GET seemed like an easy choice but the call to get a notification causes side effects, so GET is out. I ended up going with a POST to /api/notifications with a body of {subscriptionId: <SUBSCRIPTION_ID>}. Within the method we basically perform a dequeue:

var subscriptionId = req.body.subscriptionId;  Notification .findOne({_user: req.user, subscriptionId: subscriptionId, sent: false}) .exec(function(err, notification) {   if(err) { return handleError(res, err); }   notification.sent = true;   notification.save(function(err) {     if(err) { return handleError(res, err); }     return res.status(201).json(notification);   }); }); 

In the service worker we need to for sure get the subscription before we make the fetch.

self.addEventListener('push', function(event) {   event.waitUntil(     self.registration.pushManager.getSubscription().then(function(subscription) {       fetch('/api/notifications/', {         method: 'post',         headers: {           'Authorization': 'Bearer ' + self.token,           'Accept': 'application/json',           'Content-Type': 'application/json'         },         body: JSON.stringify(subscription)       })       .then(function(response) { return response.json(); })       .then(function(data) {         self.registration.showNotification(data.title, {           body: data.body,           icon: 'favicon-196x196.png'         });       })       .catch(function(err) {         console.log('err');         console.log(err);       });     })   ); }); 

It's also worth noting that the subscription object changed from Chrome 43 to Chrome 45. In Chrome 45 the subscriptionId property was removed, just something to look out for - this code was written to work with Chrome 43.

I wanted to make authenticated calls to my backend so I needed to figure out how to get the JWT from my Angular application to my service worker. I ended up using postMessage. Here's what I do after registering the service worker:

navigator.serviceWorker.register('/service-worker.js', {scope:'./'}).then(function(reg) {   var messenger = reg.installing || navigator.serviceWorker.controller;   messenger.postMessage({token: $localStorage.token}); }).catch(function(err) {   console.log('err');   console.log(err); }); 

In the service worker listen for the message:

self.onmessage.addEventListener('message', function(event) {   self.token = event.data.token; }); 

Strangely enough, that listener works in Chrome 43 but not Chrome 45. Chrome 45 works with a handler like this:

self.addEventListener('message', function(event) {   self.token = event.data.token; }); 

Right now push notifications take quite a bit of work to get something useful going - I'm really looking forward to payloads!

like image 44
Andy Gaskell Avatar answered Oct 02 '22 13:10

Andy Gaskell