From f2038e77e1192ba304e5509a9df95d7db2fe5651 Mon Sep 17 00:00:00 2001 From: Sam Lown Date: Wed, 18 Jan 2012 13:13:34 +0100 Subject: [PATCH] Adding support to automatically set the auth token if google requests it --- README.md | 42 +++++++++++++++++++++++++++++++++++++----- lib/c2dm.js | 11 ++++++++++- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 62a2932..ded0339 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ See [Google Client Login documentation][2] for details. var config = { user: 'bla-blah-blah@gmail.com', password: 'your-huge-very-very-strong-password', - source: 'yourCompany-yourMegaApp-version', + source: 'com.company.app-name', }; var c2dm = new C2DM(config); @@ -39,19 +39,23 @@ See [C2DM documentation][3] for details. var message = { registration_id: 'Device registration id', - collapse_key: 'Collapse key', + collapse_key: 'Collapse key', // required 'data.key1': 'value1', 'data.key2': 'value2', delay_while_idle: '1' // remove if not needed }; c2dm.send(message, function(err, messageId){ - + if (err) { + console.log("Something has gone wrong!"); + } else { + console.log("Sent with message ID: ", messageId); + } }); ### Avoiding login procedure -You can avoid login procedure by manually setting Google ClientLogin Auth tokin in config for connection. -First of all you need to get this token by executing next command after replacing `ROLE_EMAIL`, `ROLE_PASSWORDPASS` and `YOURCOMPANY-YOURAPP-Version` with your data: +You can avoid the login procedure by manually setting Google ClientLogin Auth token in the connection config. +First of all you need to fetch the token by executing the following command. Replace `ROLE_EMAIL`, `ROLE_PASSWORDPASS` and `YOURCOMPANY-YOURAPP-Version` with your data: $ curl -X POST https://www.google.com/accounts/ClientLogin -d Email=ROLE_EMAIL -d Passwd=ROLE_PASSWORDPASS -d accountType=HOSTED_OR_GOOGLE -d service=ac2dm -d source=YOURCOMPANY-YOURAPP-Version @@ -62,6 +66,34 @@ You will receive three lines. Skip `SID` and `LSID` and copy line starting with }; var c2dm = new C2DM(config); +However, Google will occaisionally require the token to be updated before further requests can be accepted. If this happens, the `Update-Client-Auth` header will automatically be used to update the current configurations token, but obviously will not be stored on the next reload. A `token` event will be triggered if this happens so you can update a local configuration file, but its probably easier to perform a login each time the application is started: + + c2dm.on('token', function(err, token) { + // Do something with the new token + }); + +### Testing sending a message +If it looks like things aren't going your way, try sending a request manually using the following curl command and see what google sends back to you: + + $ curl -H "Authorization: GoogleLogin auth=YOUR-LONG-TOKEN" -X POST https://android.apis.google.com/c2dm/send -d "registration_id=DESTINATION-TOKEN" -d "collapse_key=key" -d "data.event=hire" -v + +You should get back the header details along with a message id if sending has been successful. For example: + + .... sending headers and SSL stuff ..... + < HTTP/1.1 200 OK + < Content-Type: text/plain + < Date: Wed, 18 Jan 2012 11:18:01 GMT + < Expires: Wed, 18 Jan 2012 11:18:01 GMT + < Cache-Control: private, max-age=0 + < X-Content-Type-Options: nosniff + < X-Frame-Options: SAMEORIGIN + < X-XSS-Protection: 1; mode=block + < Server: GSE + < Transfer-Encoding: chunked + < + id=0:1326885481081626%900b347100019e5f + .... more SSL stuff .... + ### Keep-alive connection This module supports Connection: keep-alive header too keep connection to c2dm gate established. You could use it by simply including property in config: diff --git a/lib/c2dm.js b/lib/c2dm.js index 908c9ae..3d28e5e 100644 --- a/lib/c2dm.js +++ b/lib/c2dm.js @@ -29,6 +29,7 @@ function C2DM(config) { method: 'POST', headers: {} }; + this.on('token', this.captureToken); } util.inherits(C2DM, emitter); @@ -41,7 +42,6 @@ C2DM.prototype.captureToken = function(err, token) { C2DM.prototype.login = function(cb) { var self = this; - this.once('token', this.captureToken); if (cb) this.once('token', cb); @@ -90,6 +90,15 @@ C2DM.prototype.send = function(packet, cb) { var request = https.request(this.c2dmOptions, function(res) { var data = ''; + + // Check if we need to update the headers and try again + var newToken = res.headers['update-client-auth']; + if (newToken) { + self.emit('token', null, newToken); + self.send(packet, cb); + return; // ignore any other events from this request + } + function respond() { var idx = data.indexOf('id='); if (idx < 0) {