From 5b748f9dcbed5b4e43f17d155d9443e73280096b Mon Sep 17 00:00:00 2001 From: Eran Hammer Date: Tue, 26 May 2015 13:12:01 -0700 Subject: [PATCH 1/3] Add direct access to resource requests --- lib/oauth.js | 62 ++++++++++++++++++++++++++++++++---------------- test/mock.js | 20 +++++++++++++--- test/oauth.js | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 23 deletions(-) diff --git a/lib/oauth.js b/lib/oauth.js index 188b21d5..c96e6052 100755 --- a/lib/oauth.js +++ b/lib/oauth.js @@ -304,34 +304,45 @@ internals.Client.prototype.temporary = function (oauth_callback, callback) { }; -internals.Client.prototype.token = function (oauth_token, oauth_verifier, tokenSecret, callback) { +internals.Client.prototype.token = function (oauthToken, oauthVerifier, tokenSecret, callback) { // Token Credentials (2.3) var oauth = { - oauth_token: oauth_token, - oauth_verifier: oauth_verifier + oauth_token: oauthToken, + oauth_verifier: oauthVerifier }; this.request('post', this.settings.token, null, oauth, tokenSecret, 'token credentials', callback); }; -internals.Client.prototype.get = function (uri, params, oauth_token, tokenSecret, callback) { +internals.Client.prototype.get = function (uri, params, oauthToken, tokenSecret, callback) { + + this.resource('get', uri, params, { token: oauthToken, secret: tokenSecret }, callback); +}; + + +internals.Client.prototype.resource = function (method, uri, params, options, callback) { // Making Requests (3.1) var oauth = { - oauth_token: oauth_token + oauth_token: options.token }; - this.request('get', uri, params, oauth, tokenSecret, 'token credentials', callback); -}; + if (!options.stream) { + return this.request(method, uri, params, oauth, options.secret, 'resource', callback); + } + this._prepare(method, uri, params, oauth, options, function (method, uri, header) { + + Wreck.request(method, uri, { headers: { Authorization: header } }, callback); + }); +}; -internals.Client.prototype.request = function (method, uri, params, oauth, tokenSecret, type, callback) { - var provider = this.provider; +internals.Client.prototype._prepare = function (method, uri, params, oauth, options, next) { if (this.settings.version) { oauth.oauth_version = this.settings.version; @@ -341,23 +352,34 @@ internals.Client.prototype.request = function (method, uri, params, oauth, token oauth.oauth_timestamp = Math.floor(Date.now() / 1000).toString(); oauth.oauth_consumer_key = this.settings.clientId; oauth.oauth_signature_method = 'HMAC-SHA1'; - oauth.oauth_signature = this.signature(method, uri, params, oauth, tokenSecret); + oauth.oauth_signature = this.signature(method, uri, params, oauth, options.secret); var query = params ? ('?' + Querystring.encode(params)) : ''; - Wreck[method](uri + query, { headers: { Authorization: internals.Client.header(oauth) } }, function (err, res, payload) { + return next(method, uri + query, internals.Client.header(oauth)); +}; - if (err || - res.statusCode !== 200) { - return callback(Boom.internal('Failed obtaining ' + provider + ' ' + type, err || payload)); - } +internals.Client.prototype.request = function (method, uri, params, oauth, tokenSecret, type, callback) { - payload = internals.parse(payload); - if (payload instanceof Error) { - return callback(Boom.internal('Received invalid payload from ' + provider + ' ' + type + ' endpoint', payload)); - } + var desc = this.provider + ' ' + type; + + this._prepare(method, uri, params, oauth, { secret: tokenSecret }, function (method, uri, header) { - return callback(null, payload); + Wreck[method](uri, { headers: { Authorization: header } }, function (err, res, payload) { + + if (err || + res.statusCode !== 200) { + + return callback(Boom.internal('Failed obtaining ' + desc, err || payload)); + } + + payload = internals.parse(payload); + if (payload instanceof Error) { + return callback(Boom.internal('Received invalid payload from ' + desc + ' endpoint', payload)); + } + + return callback(null, payload); + }); }); }; diff --git a/test/mock.js b/test/mock.js index ebb0fdf0..30278a52 100755 --- a/test/mock.js +++ b/test/mock.js @@ -57,7 +57,7 @@ exports.V1 = internals.V1 = function (fail) { oauth_callback_confirmed: true }; - reply(Querystring.encode(payload)).type('application/x-www-form-urlencoded'); + return reply(Querystring.encode(payload)).type('application/x-www-form-urlencoded'); } } }, @@ -75,7 +75,7 @@ exports.V1 = internals.V1 = function (fail) { token.verifier = '123'; var extra = Object.keys(request.query).length > 1 ? '&extra=true' : ''; - reply().redirect(unescape(token.callback) + '?oauth_token=' + request.query.oauth_token + '&oauth_verifier=' + token.verifier + extra); + return reply().redirect(unescape(token.callback) + '?oauth_token=' + request.query.oauth_token + '&oauth_verifier=' + token.verifier + extra); } } }, @@ -106,7 +106,21 @@ exports.V1 = internals.V1 = function (fail) { payload.screen_name = 'Steve Stevens'; } - reply(Querystring.encode(payload)).type('application/x-www-form-urlencoded'); + return reply(Querystring.encode(payload)).type('application/x-www-form-urlencoded'); + } + } + }, + { + method: '*', + path: '/resource', + config: { + bind: this, + handler: function (request, reply) { + + var header = Hawk.utils.parseAuthorizationHeader(request.headers.authorization.replace(/OAuth/i, 'Hawk'), ['realm', 'oauth_consumer_key', 'oauth_token', 'oauth_signature_method', 'oauth_verifier', 'oauth_signature', 'oauth_version', 'oauth_timestamp', 'oauth_nonce']); + expect(header.oauth_token).to.equal('final'); + + return reply('some text reply'); } } } diff --git a/test/oauth.js b/test/oauth.js index 5ad79a74..1e0d0f74 100755 --- a/test/oauth.js +++ b/test/oauth.js @@ -430,6 +430,7 @@ describe('Bell', function () { }); }); }); + it('forces https in callback_url when set in options', function (done) { var mock = new Mock.V1(); @@ -479,6 +480,7 @@ describe('Bell', function () { }); }); }); + it('uses location setting in callback_url when set in options', function (done) { var mock = new Mock.V1(); @@ -528,6 +530,69 @@ describe('Bell', function () { }); }); }); + + it('returns resource response stream', { parallel: false }, function (done) { + + var mock = new Mock.V1(); + mock.start(function (provider) { + + var server = new Hapi.Server(); + server.connection({ host: 'localhost', port: 80 }); + server.register(Bell, function (err) { + + expect(err).to.not.exist(); + + server.auth.strategy('custom', 'bell', { + password: 'password', + isSecure: false, + clientId: 'test', + clientSecret: 'secret', + provider: provider + }); + + server.route({ + method: '*', + path: '/login', + config: { + auth: 'custom', + handler: function (request, reply) { + + var client = new Bell.oauth.Client({ + name: 'twitter', + provider: provider, + clientId: 'test', + clientSecret: 'secret' + }); + + var credentials = request.auth.credentials; + client.resource('GET', mock.uri + '/resource', null, { token: credentials.token, secret: credentials.secret, stream: true }, function (err, res) { + + expect(err).to.not.exist(); + return reply(res); + }); + } + } + }); + + server.inject('/login?next=%2Fhome', function (res) { + + var cookie = res.headers['set-cookie'][0].split(';')[0] + ';'; + expect(res.headers.location).to.equal(mock.uri + '/auth?oauth_token=1'); + + mock.server.inject(res.headers.location, function (res) { + + expect(res.headers.location).to.equal('http://localhost:80/login?oauth_token=1&oauth_verifier=123'); + + server.inject({ url: res.headers.location, headers: { cookie: cookie } }, function (res) { + + expect(res.result).to.equal('some text reply'); + mock.stop(done); + }); + }); + }); + }); + }); + }); }); describe('#v2', function () { From aba9ccdba298a52716130b8e781fbed653ca77d3 Mon Sep 17 00:00:00 2001 From: Eran Hammer Date: Tue, 26 May 2015 13:14:46 -0700 Subject: [PATCH 2/3] 2.9.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 482b8a2a..d82505c0 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "bell", "description": "Third-party login plugin for hapi", - "version": "2.8.0", + "version": "2.9.0", "repository": "git://github.com/hapijs/bell", "main": "lib/index.js", "keywords": [ From 5c21a2f59e2773b7fed8d4cedbdefe91b5b70b51 Mon Sep 17 00:00:00 2001 From: Eran Hammer Date: Wed, 27 May 2015 00:51:13 -0700 Subject: [PATCH 3/3] Lowercase method --- lib/oauth.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/oauth.js b/lib/oauth.js index c96e6052..3f306abe 100755 --- a/lib/oauth.js +++ b/lib/oauth.js @@ -365,7 +365,7 @@ internals.Client.prototype.request = function (method, uri, params, oauth, token this._prepare(method, uri, params, oauth, { secret: tokenSecret }, function (method, uri, header) { - Wreck[method](uri, { headers: { Authorization: header } }, function (err, res, payload) { + Wreck[method.toLowerCase()](uri, { headers: { Authorization: header } }, function (err, res, payload) { if (err || res.statusCode !== 200) {