Push notifications in Progressive web app through GCM - javascript

while sending push notification i got ( Uncaught (in promise) ReferenceError: require is not defined(…)) error.here is my code
const endPoint = subscription.endpoint.slice(subscription.endpoint.lastIndexOf('/')+1);
console.log(endPoint);
var gcm = require('node-gcm');
var message = new gcm.Message({
notification: {
title: "Hello, World",
icon: "ic_launcher",
body: "This is a notification that will be displayed ASAP.",
tag:"hello"
}
});
var regTokens = [endPoint];
var sender = new gcm.Sender('AIzaSyD9Bcxd_MQZFoGjO1y_hPm-xUdgnM25Ny4'); //API Key
// Now the sender can be used to send messages
sender.send(message, { registrationTokens: regTokens }, function (error, response) {
if (error) {
console.error(error);
res.status(400);
}
else {
console.log(response);
res.status(200);
}
});
})
})
}
Screenshot of error
enter image description here

This code uses require, so it looks to me like you're trying to use node code in the browser. To do that you'll need to use something like Browserify, although I'm not sure that's going to work for node-gcm as it may have certain requirements about sending network requests without cross origin restrictions etc.

Related

Permission Issue when trying to verify Google Play Subscription with NodeJS google-play-billing-validator

I am trying to verify Subscription Purchase from Android App ( Google Play ) on my server side using node and google-play-billing-validator package. I have followed the instruction and added services account along with accounts permission ( tried both only account and admin ) but its still returns me with insufficient permissions . I don't know why its doing that and whats wrong .
var Verifier = require('google-play-billing-validator');
var options = {
"email": '###########################',
"key": "PRIVATE",
};
try {
var verifier = new Verifier(options);
let receipt = {
packageName: "com.tech.ichat",
productId:
"mychat_bms1",
purchaseToken: "hajlffdcmmkdijnilkogpih.AO-J1OwYTQjVf57Exl8eJBRVNo4VLfwlWIOJykDfyASPLx9YbxvWwP0qDqls14Llcyt8cyslTCT4fN-Xy-0Vg-9BETVnTrxpPQ"
};
let promiseData = verifier.verifySub(receipt)
promiseData.then(function (response) {
// Yay! Subscription is valid
// See response structure below
console.log('API SUCCESS RESPONSE', error);
})
.then(function (response) {
// Here for example you can chain your work if subscription is valid
// eg. add coins to the user profile, etc
// If you are new to promises API
// Awesome docs: https://developers.google.com/web/fundamentals/primers/promises
})
.catch(function (error) {
// Subscription is not valid or API error
// See possible error messages below
console.error(error);
});
} catch (error) {
console.error('Exception Handled', error);
}
response I got .
{
isSuccessful: false,
errorCode: 401,
errorMessage: 'The current user has insufficient permissions to perform the requested operation.'
}

Access Denied error AWS Transcription Node JS API

I am using AWS transcription API on Node JS with following code
const tClient = new TranscribeClient({
region: "us-east-1",
credentials: {
accessKeyId: AWS_ID,
secretAccessKey: SECRET,
}
});
const params = {
TranscriptionJobName: "firstjob",
LanguageCode: "en-US", // For example, 'en-US'
MediaFormat: "m4a", // For example, 'wav'
Media: {
MediaFileUri: "https://transcribe-demo.s3-REGION.amazonaws.com/hello_world.m4a",
},
};
const run = async () => {
try {
const data = await tClient.send(
new StartTranscriptionJobCommand(params)
);
console.log("Success - put", data);
return data; // For unit tests.
} catch (err) {
console.log("Error", err);
}
};
run();
But I am getting following error, I have checked all the permissions and access keys are correct . I am unable to understand error reason.
AccessDeniedException: User: arn:aws:iam::494240200407:user/demno_system is not authorized to perform: transcribe:StartTranscriptionJob on resource: arn:aws:transcribe:us-east-1:494240200407:transcription-job/firstjob because no permissions boundary allows the transcribe:StartTranscriptionJob action
Any inputs are appreciated.
As stated in the error message, you have a permission boundary that doesn't allow this action. The fact that you added the required policy to the user has no effect, since the access is limited by the permission boundary. You need to edit the user's permission boundary to allow this.
Refer to the documentation.

Actions Sdk get this error TypeError: Cannot read property 'output' of undefined

I'm trying to connect IBM Watson and Google Assistant, but I keep receiving this error "TypeError: Cannot read property 'output' of undefined" and this "Function execution took 3323 ms, finished with status: 'crash'"
This is my code:
const {actionssdk} = require('actions-on-google');
const functions = require('firebase-functions');
const app = actionssdk({debug: true});
app.intent('actions.intent.MAIN', (conv) => {
conv.ask('Olá, como posso lhe ajudar?');
});
app.intent('actions.intent.TEXT', (conv, input) => {
var AssistantV1 = require('watson-developer-cloud/assistant/v1');
var assistant = new AssistantV1({
username: '###################################',
password: '###################################',
url: '###################################',
version: '2018-07-10'
});
conv.ask("eeeeeeeeeeeeeeeee");
return new Promise( (resolve, reject) => {
assistant.message(
{
workspace_id: '###################################',
input: { text: input },
headers: {'Content-Type':'application/json'}
},
function(err, response) {
conv.ask(response.output.text[0]);
resolve();
}
);
})
});
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);
Rebeca, just to adding information, you are trying to add some outbound access, but you need to configure your account to do that.
"Billing account not configured. External network is not accessible
and quotas are severely limited. Configure billing account to remove
these restrictions"
If you wanted to call some API (IBM Watson, as verified) you'd need to enable billing.
For the other quotas, take a look here to see prices - as you can see there are limits to the number of invocations using free tier.
Your responseobject is null. Check it is not equal to null before to use it:
let speech;
if (response !== null) {
speech = response.output.text[0];
}
else{
speech = "I'm sorry, there was an error and I'm unable to answer";
}
conv.ask(speech);

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

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?
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.
#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!
Actually, payload should be implemented in Chrome 50 (release date - April 19, 2016). In Chrome 50 (and in the current version of Firefox on desktop) you can send some arbitrary data along with the push so that the client can avoid making the extra request. All payload data must be encrypted.
Here is the the encryption details from developer : https://developers.google.com/web/updates/2016/03/web-push-encryption?hl=en
I just ran into this problem. Newer versions of firefox and chrome( version 50+) support payload transferring. The dev docs here details the implementation on how this works. An important thing to note is that google GCM or possibly client/chome (I dont know which one) will actually ignore the payload entirely if it is not encrypted.
This website has both client/server implementations of how to do the push and retrieval through service workers. The push library that examples use is merely a wrapper around a normal REST call
service worker example implementation:
self.addEventListener('push', function(event) {
var payload = event.data ? event.data.text() : 'no payload';
event.waitUntil(
self.registration.showNotification('ServiceWorker Cookbook', {
body: payload,
})
);
});
Server example implementation:
var webPush = require('web-push');
webPush.setGCMAPIKey(process.env.GCM_API_KEY);
module.exports = function(app, route) {
app.post(route + 'register', function(req, res) {
res.sendStatus(201);
});
app.post(route + 'sendNotification', function(req, res) {
setTimeout(function() {
webPush.sendNotification(req.body.endpoint, {
TTL: req.body.ttl,
payload: req.body.payload,
userPublicKey: req.body.key,
userAuth: req.body.authSecret,
}).then(function() {
res.sendStatus(201);
});
}, req.body.delay * 1000);
});
};
Client side javascript implementation example of printing out the the required fields.
navigator.serviceWorker.register('serviceWorker.js')
.then(function(registration) {
return registration.pushManager.getSubscription()
.then(function(subscription) {
if (subscription) {
return subscription;
}
return registration.pushManager.subscribe({
userVisibleOnly: true
});
});
}).then(function(subscription) {
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;
console.log("Endpoint: " + endpoint);
console.log("Key: " + key);
console.log("AuthSecret: " + authSecret);
});
To retrieve that data, you need to parse "event.data.text()" to a JSON object. I'm guessing something was updated since you tried to get this to work, but it works now. Unlucky!
However, since I made it to this post when searching for a solution myself, others would probably like a working answer. Here it is:
// Push message event handler
self.addEventListener('push', function(event) {
// If true, the event holds data
if(event.data){
// Need to parse to JSON format
// - Consider event.data.text() the "stringify()"
// version of the data
var payload = JSON.parse(event.data.text());
// For those of you who love logging
console.log(payload);
var title = payload.data.title;
var body = payload.data.body;
var icon = './assets/icons/icon.ico'
var tag = 'notification-tag';
// Wait until payload is fetched
event.waitUntil(
self.registration.showNotification(title, {
body: body,
icon: icon,
tag: tag,
data: {} // Keeping this here in case I need it later
})
);
} else {
console.log("Event does not have data...");
}
}); // End push listener
// Notification Click event
self.addEventListener('notificationclick', function(event) {
console.log("Notification Clicked");
}); // End click listener
Personally, I will be creating a "generic" notification in case my data is funky, and will also be using try/catch. I suggest doing the same.
Follow these steps to achieve this:
In the browser:
You need to get the subscription object and save it, so your server has access to it: Read more about it
navigator.serviceWorker.ready.then(serviceWorkerRegistration => {
serviceWorkerRegistration.pushManager.subscribe({userVisibleOnly: true})
.then(subscription => {
//save subscription.toJSON() object to your server
})});
In the server:
install web-push npm package
And send a web push like this:
const webpush = require('web-push');
setImmediate(async () => {
const params = {
payload: {title: 'Hey', body: 'Hello World'}
};
//this is the subscription object you should get in the browser. This is a demo of how it should look like
const subscription = {"endpoint":"https://android.googleapis.com/gcm/send/deC24xZL8z4:APA91bE9ZWs2KvLdo71NGYvBHGX6ZO4FFIQCppMsZhiTXtM1S2SlAqoOPNxzLlPye4ieL2ulzzSvPue-dGFBszDcFbSkfb_VhleiJgXRA8UwgLn5Z20_77WroZ1LofWQ22g6bpIGmg2JwYAqjeca_gzrZi3XUpcWHfw","expirationTime":null,"keys":{"p256dh":"BG55fZ3zZq7Cd20vVouPXeVic9-3pa7RhcR5g3kRb13MyJyghTY86IO_IToVKdBmk_2kA9znmbqvd0-o8U1FfA3M","auth":"1gNTE1wddcuF3FUPryGTZOA"}};
if (subscription.keys) {
params.userPublicKey = subscription.keys.p256dh;
params.userAuth = subscription.keys.auth;
}
// this key you should take from firebase console for example
// settings -> cloud messaging -> Server key
webpush.setGCMAPIKey('AAAASwYmslc:APfA91bGy3tdKvuq90eOvz4AoUm6uPtbqZktZ9dAnElrlH4gglUiuvereTJJWxz8_dANEQciX9legijnJrxvlapI84bno4icD2D0cdVX3_XBOuW3aWrpoqsoxLDTdth86CjkDD4JhqRzxV7RrDXQZd_sZAOpC6f32nbA');
try {
const r = await webpush.sendNotification(subscription, JSON.stringify(params));
console.log(r);
}
catch (e) {
console.error(e);
}
});

Azure Mobile Services - Getting more user information

I inherited a Windows 8 application that is written with XAML. So in C# when I make this call
user = await MobileServices.MobileService
.LoginAsync(MobileServiceAuthenticationProvider.MicrosoftAccount);
(This is for Azure Mobile Services)
The user object is ONLY giving me the Token and the MicrosoftAccount:..............
In order to get to authenticate people, I need to be able to see WHO is requesting access...
I looking at articles like below, but I seem to be missing something? Is this javascript in the article something I would have to write in Node.js?
Example article:
http://blogs.msdn.com/b/carlosfigueira/archive/2013/12/12/expanded-login-scopes-in-azure-mobile-services.aspx
Currently to be able to get more information about the logged in user, you need to make a second call to the service to retrieve the user info. You don't really need to ask for additional login scopes (the topic of the post you mentioned) to retrieve the user name, since that is given by default for all the providers.
This post should have the code you need to write in the server side (node.js) to get more information about the logged in user. The TL;DR version is given below:
On the server side: add this custom API (I'll call it "userInfo"; set the permission of GET to "user", and all others to admin):
exports.get = function(request, response) {
var user = request.user;
user.getIdentities({
success: function(identities) {
var accessToken = identities.microsoft.accessToken;
var url = 'https://apis.live.net/v5.0/me/?method=GET&access_token=' + accessToken;
var requestCallback = function (err, resp, body) {
if (err || resp.statusCode !== 200) {
console.error('Error sending data to the provider: ', err);
response.send(statusCodes.INTERNAL_SERVER_ERROR, body);
} else {
try {
var userData = JSON.parse(body);
response.send(200, userData);
} catch (ex) {
console.error('Error parsing response from the provider API: ', ex);
response.send(statusCodes.INTERNAL_SERVER_ERROR, ex);
}
}
}
var req = require('request');
var reqOptions = {
uri: url,
headers: { Accept: "application/json" }
};
req(reqOptions, requestCallback);
}
});
}
On the client side, after a successful login, call that API:
user = await MobileServices.MobileService
.LoginAsync(MobileServiceAuthenticationProvider.MicrosoftAccount);
var userInfo = await MobileServices.MobileService.InvokeApiAsync(
"userInfo", HttpMethod.Get, null);
userInfo will contain a JObject with the user information. There is an open feature request to make this better at http://feedback.azure.com/forums/216254-mobile-services/suggestions/5211616-ability-to-intercept-the-login-response.

Categories