From e8adcc06847b103d50587155dacc93d4415dd9df Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Wed, 23 Jul 2014 00:55:19 -0700 Subject: [PATCH 1/2] Adding package.json to manage dependencies. --- package.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 package.json diff --git a/package.json b/package.json new file mode 100644 index 0000000..513467e --- /dev/null +++ b/package.json @@ -0,0 +1,7 @@ +{ + "repository": "https://github.com/oftn/oftn-bot", + "dependencies": { + "twitter": "~0.1.17" + } +} + From c69444b4e32cfedb24a64233e00f99c243f5eccb Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Wed, 23 Jul 2014 00:56:53 -0700 Subject: [PATCH 2/2] Upgrading the `twitter` module. --- node_modules/twitter/.npmignore | 4 +- node_modules/twitter/README.md | 42 +- node_modules/twitter/lib/twitter.js | 109 +++-- .../twitter/node_modules/cookie/LICENSE.txt | 20 - .../node_modules/cookie/README.markdown | 57 --- .../node_modules/cookie/example/ex1.js | 14 - .../twitter/node_modules/cookie/index.js | 161 -------- .../twitter/node_modules/cookie/package.json | 6 - .../twitter/node_modules/oauth/.gitignore | 1 - .../twitter/node_modules/oauth/Makefile | 4 +- .../twitter/node_modules/oauth/Readme.md | 188 +++++++-- .../node_modules/oauth/debian/changelog | 26 -- .../twitter/node_modules/oauth/debian/compat | 1 - .../twitter/node_modules/oauth/debian/control | 13 - .../node_modules/oauth/debian/copyright | 9 - .../twitter/node_modules/oauth/debian/dirs | 1 - .../twitter/node_modules/oauth/debian/install | 2 - .../twitter/node_modules/oauth/debian/rules | 3 - .../node_modules/oauth/debian/source/format | 1 - .../oauth/examples/term.ie.oauth-HMAC-SHA1.js | 24 +- .../oauth/examples/term.ie.oauth-PLAINTEXT.js | 34 -- .../oauth/examples/twitter-test.js | 34 -- .../twitter/node_modules/oauth/fapp.js | 27 -- .../twitter/node_modules/oauth/google-test.js | 29 -- .../twitter/node_modules/oauth/lib/_utils.js | 2 +- .../twitter/node_modules/oauth/lib/oauth.js | 115 ++++-- .../node_modules/oauth/lib/oauth.js.orig | 391 ------------------ .../twitter/node_modules/oauth/lib/oauth2.js | 103 ++++- .../twitter/node_modules/oauth/lib/poo.diff | 136 ------ .../node_modules/oauth/merge_coopernurse | 0 .../twitter/node_modules/oauth/numero-test.js | 29 -- .../twitter/node_modules/oauth/package.json | 46 ++- .../twitter/node_modules/oauth/test.js | 29 -- .../twitter/node_modules/oauth/testb.js | 35 -- .../twitter/node_modules/oauth/tests/oauth.js | 370 +++++++++++++++-- .../node_modules/oauth/tests/oauth2.js | 241 ++++++++++- node_modules/twitter/package.json | 83 +++- package.json | 2 +- 38 files changed, 1101 insertions(+), 1291 deletions(-) delete mode 100644 node_modules/twitter/node_modules/cookie/LICENSE.txt delete mode 100644 node_modules/twitter/node_modules/cookie/README.markdown delete mode 100644 node_modules/twitter/node_modules/cookie/example/ex1.js delete mode 100644 node_modules/twitter/node_modules/cookie/index.js delete mode 100644 node_modules/twitter/node_modules/cookie/package.json delete mode 100644 node_modules/twitter/node_modules/oauth/.gitignore delete mode 100644 node_modules/twitter/node_modules/oauth/debian/changelog delete mode 100644 node_modules/twitter/node_modules/oauth/debian/compat delete mode 100644 node_modules/twitter/node_modules/oauth/debian/control delete mode 100644 node_modules/twitter/node_modules/oauth/debian/copyright delete mode 100644 node_modules/twitter/node_modules/oauth/debian/dirs delete mode 100644 node_modules/twitter/node_modules/oauth/debian/install delete mode 100755 node_modules/twitter/node_modules/oauth/debian/rules delete mode 100644 node_modules/twitter/node_modules/oauth/debian/source/format delete mode 100644 node_modules/twitter/node_modules/oauth/examples/term.ie.oauth-PLAINTEXT.js delete mode 100644 node_modules/twitter/node_modules/oauth/examples/twitter-test.js delete mode 100644 node_modules/twitter/node_modules/oauth/fapp.js delete mode 100644 node_modules/twitter/node_modules/oauth/google-test.js delete mode 100644 node_modules/twitter/node_modules/oauth/lib/oauth.js.orig delete mode 100644 node_modules/twitter/node_modules/oauth/lib/poo.diff delete mode 100644 node_modules/twitter/node_modules/oauth/merge_coopernurse delete mode 100644 node_modules/twitter/node_modules/oauth/numero-test.js delete mode 100644 node_modules/twitter/node_modules/oauth/test.js delete mode 100644 node_modules/twitter/node_modules/oauth/testb.js diff --git a/node_modules/twitter/.npmignore b/node_modules/twitter/.npmignore index c35e278..158d9fe 100644 --- a/node_modules/twitter/.npmignore +++ b/node_modules/twitter/.npmignore @@ -1,3 +1,3 @@ -test +node_modules +.*.swp s*.js -index.html diff --git a/node_modules/twitter/README.md b/node_modules/twitter/README.md index 77a7c8b..71c3231 100644 --- a/node_modules/twitter/README.md +++ b/node_modules/twitter/README.md @@ -1,15 +1,15 @@ -Asynchronous Twitter client API for node.js -=========================================== +Twitter API client library for node.js +====================================== -[node-twitter](https://github.com/jdub/node-twitter) aims to provide a complete, asynchronous client library for Twitter (and other compliant endpoints), including REST, stream and search APIs. It was inspired by, and uses some code from, technoweenie's [twitter-node](https://github.com/technoweenie/twitter-node). +[node-twitter](https://github.com/jdub/node-twitter) aims to provide a complete, asynchronous client library for the Twitter API, including the REST, search and streaming endpoints. It was inspired by, and uses some code from, [@technoweenie](https://github.com/technoweenie)'s [twitter-node](https://github.com/technoweenie/twitter-node). ## Requirements You can install node-twitter and its dependencies with npm: `npm install twitter`. -- [node](http://nodejs.org/) v0.2+ +- [node](http://nodejs.org/) v0.6+ - [node-oauth](https://github.com/ciaranj/node-oauth) -- [cookie-node](https://github.com/jed/cookie-node) +- [cookies](https://github.com/jed/cookies) ## Getting started @@ -17,8 +17,8 @@ It's early days for node-twitter, so I'm going to assume a fair amount of knowle ### Setup API (stable) - var sys = require('sys'), - twitter = require('twitter'); + var util = require('util'), + twitter = require('twitter'); var twit = new twitter({ consumer_key: 'STATE YOUR NAME', consumer_secret: 'STATE YOUR NAME', @@ -31,7 +31,7 @@ It's early days for node-twitter, so I'm going to assume a fair amount of knowle The convenience APIs aren't finished, but you can get started with the basics: twit.get('/statuses/show/27593302936.json', {include_entities:true}, function(data) { - sys.puts(sys.inspect(data)); + console.log(util.inspect(data)); }); ### REST API (unstable, may change) @@ -39,19 +39,19 @@ The convenience APIs aren't finished, but you can get started with the basics: Note that all functions may be chained: twit - .verifyCredentials(function (data) { - sys.puts(sys.inspect(data)); + .verifyCredentials(function(data) { + console.log(util.inspect(data)); }) .updateStatus('Test tweet from node-twitter/' + twitter.VERSION, - function (data) { - sys.puts(sys.inspect(data)); + function(data) { + console.log(util.inspect(data)); } ); ### Search API (unstable, may change) twit.search('nodejs OR #node', function(data) { - sys.puts(sys.inspect(data)); + console.log(util.inspect(data)); }); ### Streaming API (stable) @@ -59,16 +59,16 @@ Note that all functions may be chained: The stream() callback receives a Stream-like EventEmitter: twit.stream('statuses/sample', function(stream) { - stream.on('data', function (data) { - sys.puts(sys.inspect(data)); + stream.on('data', function(data) { + console.log(util.inspect(data)); }); }); node-twitter also supports user and site streams: twit.stream('user', {track:'nodejs'}, function(stream) { - stream.on('data', function (data) { - sys.puts(sys.inspect(data)); + stream.on('data', function(data) { + console.log(util.inspect(data)); }); // Disconnect stream after five seconds setTimeout(stream.destroy, 5000); @@ -76,11 +76,11 @@ node-twitter also supports user and site streams: ## Contributors -- [Jeff Waugh](http://github.com/jdub) (author) -- [rick](http://github.com/technoweenie) (parser.js and, of course, twitter-node!) +- [Jeff Waugh](https://github.com/jdub) (author) +- [@technoweenie](https://github.com/technoweenie) (parser.js and, of course, twitter-node!) +- Lots of [wonderful helper elves](https://github.com/jdub/node-twitter/contributors) on GitHub ## TODO - Complete the convenience functions, preferably generated -- Support [recommended reconnection behaviour](http://dev.twitter.com/pages/user_streams_suggestions) for the streaming APIs -- Should probably implement basic auth for non-Twitter endpoints +- Fix ALL THE THINGS! on the GitHub [issues list](https://github.com/jdub/node-twitter/issues) diff --git a/node_modules/twitter/lib/twitter.js b/node_modules/twitter/lib/twitter.js index 1123b1f..14b0ffd 100644 --- a/node_modules/twitter/lib/twitter.js +++ b/node_modules/twitter/lib/twitter.js @@ -1,8 +1,9 @@ -var VERSION = '0.1.17', +var VERSION = '0.1.18', http = require('http'), querystring = require('querystring'), oauth = require('oauth'), - cookie = require('cookie'), + Cookies = require('cookies'), + Keygrip = require('keygrip'), streamparser = require('./parser'); function merge(defaults, options) { @@ -37,12 +38,13 @@ function Twitter(options) { access_token_url: 'https://api.twitter.com/oauth/access_token', authenticate_url: 'https://api.twitter.com/oauth/authenticate', authorize_url: 'https://api.twitter.com/oauth/authorize', + callback_url: null, - rest_base: 'https://api.twitter.com/1', - search_base: 'http://search.twitter.com', - stream_base: 'http://stream.twitter.com/1', - user_stream_base: 'https://userstream.twitter.com/2', - site_stream_base: 'http://sitestream.twitter.com/2b', + rest_base: 'https://api.twitter.com/1.1', + stream_base: 'https://stream.twitter.com/1.1', + search_base: 'https://api.twitter.com/1.1/search', + user_stream_base: 'https://userstream.twitter.com/1.1', + site_stream_base: 'https://sitestream.twitter.com/1.1', secure: false, // force use of https for login/gatekeeper cookie: 'twauth', @@ -51,12 +53,17 @@ function Twitter(options) { }; this.options = merge(defaults, options); + this.keygrip = this.options.cookie_secret === null ? null : + new Keygrip([this.options.cookie_secret]); + this.oauth = new oauth.OAuth( this.options.request_token_url, this.options.access_token_url, this.options.consumer_key, this.options.consumer_secret, - '1.0', null, 'HMAC-SHA1', null, + '1.0A', + this.options.callback_url, + 'HMAC-SHA1', null, this.options.headers); } Twitter.VERSION = VERSION; @@ -172,7 +179,7 @@ Twitter.prototype.search = function(q, params, callback) { return this; } - var url = this.options.search_base + '/search.json'; + var url = this.options.search_base + '/tweets.json'; params = merge(params, {q:q}); this.get(url, params, callback); return this; @@ -209,9 +216,10 @@ Twitter.prototype.stream = function(method, params, callback) { var url = stream_base + '/' + escape(method) + '.json'; - var request = this.oauth.post(url + '?' + querystring.stringify(params), + var request = this.oauth.post(url, this.options.access_token_key, - this.options.access_token_secret); + this.options.access_token_secret, + params); var stream = new streamparser(); stream.destroy = function() { @@ -252,12 +260,8 @@ Twitter.prototype.stream = function(method, params, callback) { */ Twitter.prototype.cookie = function(req) { // Fetch the cookie - try { - var twauth = JSON.parse(req.getSecureCookie(this.options.cookie)); - } catch (error) { - var twauth = null; - } - return twauth; + var cookies = new Cookies(req, null, this.keygrip); + return this._readCookie(cookies); } Twitter.prototype.login = function(mount, success) { @@ -270,10 +274,6 @@ Twitter.prototype.login = function(mount, success) { // Use secure cookie if forced to https and haven't configured otherwise if ( this.options.secure && !this.options.cookie_options.secure ) this.options.cookie_options.secure = true; - // Set up the cookie encryption secret if we've been given one - if ( !cookie.secret && this.options.cookie_secret !== null ) - cookie.secret = this.options.cookie_secret; - // FIXME: ^ so configs that don't use login() won't work? return function handle(req, res, next) { var path = url.parse(req.url, true); @@ -291,7 +291,8 @@ Twitter.prototype.login = function(mount, success) { } // Fetch the cookie - var twauth = self.cookie(req); + var cookies = new Cookies(req, res, self.keygrip); + var twauth = self._readCookie(cookies); // We have a winner, but they're in the wrong place if ( twauth && twauth.user_id && twauth.access_token_secret ) { @@ -314,7 +315,7 @@ Twitter.prototype.login = function(mount, success) { // FIXME: do something more intelligent return next(500); } else { - res.setSecureCookie(self.options.cookie, JSON.stringify({ + cookies.set(self.options.cookie, JSON.stringify({ user_id: user_id, screen_name: screen_name, access_token_key: access_token_key, @@ -334,7 +335,7 @@ Twitter.prototype.login = function(mount, success) { // FIXME: do something more intelligent return next(500); } else { - res.setSecureCookie(self.options.cookie, JSON.stringify({ + cookies.set(self.options.cookie, JSON.stringify({ oauth_token: oauth_token, oauth_token_secret: oauth_token_secret }), self.options.cookie_options); @@ -350,7 +351,7 @@ Twitter.prototype.login = function(mount, success) { // Broken cookie, clear it and return to originating page // FIXME: this is dumb } else { - res.clearCookie(self.options.cookie); + cookies.set(self.options.cookie, null, self.options.cookie_options); res.writeHead(302, {'Location': mount}); res.end(); return; @@ -391,50 +392,50 @@ Twitter.prototype.gatekeeper = function(failure) { // Timeline resources -Twitter.prototype.getPublicTimeline = function(params, callback) { - var url = '/statuses/public_timeline.json'; +Twitter.prototype.getHomeTimeline = function(params, callback) { + var url = '/statuses/home_timeline.json'; this.get(url, params, callback); return this; } -Twitter.prototype.getHomeTimeline = function(params, callback) { - var url = '/statuses/home_timeline.json'; +Twitter.prototype.getMentions = function(params, callback) { + var url = '/statuses/mentions.json'; this.get(url, params, callback); return this; } -Twitter.prototype.getFriendsTimeline = function(params, callback) { - var url = '/statuses/friends_timeline.json'; +Twitter.prototype.getRetweetedByMe = function(params, callback) { + var url = '/statuses/retweeted_by_me.json'; this.get(url, params, callback); return this; } -Twitter.prototype.getUserTimeline = function(params, callback) { - var url = '/statuses/user_timeline.json'; +Twitter.prototype.getRetweetedToMe = function(params, callback) { + var url = '/statuses/retweeted_to_me.json'; this.get(url, params, callback); return this; } -Twitter.prototype.getMentions = function(params, callback) { - var url = '/statuses/mentions.json'; +Twitter.prototype.getRetweetsOfMe = function(params, callback) { + var url = '/statuses/retweets_of_me.json'; this.get(url, params, callback); return this; } -Twitter.prototype.getRetweetedByMe = function(params, callback) { - var url = '/statuses/retweeted_by_me.json'; +Twitter.prototype.getUserTimeline = function(params, callback) { + var url = '/statuses/user_timeline.json'; this.get(url, params, callback); return this; } -Twitter.prototype.getRetweetedToMe = function(params, callback) { - var url = '/statuses/retweeted_to_me.json'; +Twitter.prototype.getRetweetedToUser = function(params, callback) { + var url = '/statuses/retweeted_to_user.json'; this.get(url, params, callback); return this; } -Twitter.prototype.getRetweetsOfMe = function(params, callback) { - var url = '/statuses/retweets_of_me.json'; +Twitter.prototype.getRetweetedByUser = function(params, callback) { + var url = '/statuses/retweeted_by_user.json'; this.get(url, params, callback); return this; } @@ -481,7 +482,7 @@ Twitter.prototype.retweetStatus = function(id, callback) { Twitter.prototype.getRetweets = function(id, params, callback) { var url = '/statuses/retweets/' + escape(id) + '.json'; - this.post(url, params, null, callback); + this.get(url, params, callback); return this; } @@ -1098,6 +1099,20 @@ Twitter.prototype.geoGetPlace = function(place_id, callback) { // Search resources +// Deprecated resources + +Twitter.prototype.getPublicTimeline = function(params, callback) { + var url = '/statuses/public_timeline.json'; + this.get(url, params, callback); + return this; +} + +Twitter.prototype.getFriendsTimeline = function(params, callback) { + var url = '/statuses/friends_timeline.json'; + this.get(url, params, callback); + return this; +} + /* * INTERNAL UTILITY FUNCTIONS @@ -1132,3 +1147,13 @@ Twitter.prototype._getUsingCursor = function(url, params, callback) { return this; } + +Twitter.prototype._readCookie = function(cookies) { + // parse the auth cookie + try { + var twauth = JSON.parse(cookies.get(this.options.cookie)); + } catch (error) { + var twauth = null; + } + return twauth; +} diff --git a/node_modules/twitter/node_modules/cookie/LICENSE.txt b/node_modules/twitter/node_modules/cookie/LICENSE.txt deleted file mode 100644 index 7b5b810..0000000 --- a/node_modules/twitter/node_modules/cookie/LICENSE.txt +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2010 Jed Schmidt, http://jedschmidt.com/ - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/twitter/node_modules/cookie/README.markdown b/node_modules/twitter/node_modules/cookie/README.markdown deleted file mode 100644 index 14d3b4f..0000000 --- a/node_modules/twitter/node_modules/cookie/README.markdown +++ /dev/null @@ -1,57 +0,0 @@ -cookie-node.js -============ - -# NOTE: This library has been deprecated. - -Please use [Cookies](/jed/cookies) instead. Not only is it built on the latest version of node.js without any cruft from older versions, but the signing mechanism has been factored out into [Keygrip](/jed/keygrip), a more flexible and performant library. - -`cookie-node` is a cookie module for [node.js](http://nodejs.org/), based -loosely on Tornado's approach to [signed cookies](http://www.tornadoweb.org/documentation#cookies-and-secure-cookies). - -To start, require the library in your app: - - var cookie = require( "./cookie-node" ); - -This extends the `ServerRequest` and `ServerResponse` objects, allowing you to -get cookies on requests and set them on responses for server calls: - - function( req, res ) { - var name = req.getCookie( "name" ), - length = name.length; - - res.setCookie( "name_length", length ); - - res.writeHead(200, {"Content-Type": "text/html"}); - res.write( "Your name has " + length + " characters." ); - res.close(); - } - -You can also set a cookie secret to enable signed cookies, and prevent forged -cookies: - - cookie.secret = "myRandomSecretThatNoOneWillGuess"; - -so that the above becomes: - - function( req, res ) { - var name = req.getSecureCookie( "name" ), - length = name.length; - - res.setSecureCookie( "name_length", length ); - - res.writeHead(200, {"Content-Type": "text/html"}); - res.write( "Your name has " + length + " characters." ); - res.close(); - } - -(You don't need to set the secret, but your cookies will end up being -invalidated when the server restarts, and you will be yelled at.) - -When you set a secure cookie, the value is stored alongside its expiration -date, as well as an HMAC SHA-1 digest of the two values with your secret. If a -cookie's signature does not match that calculated on the server, the -`getSecureCookie` method throws. - -If you'd like to clear a cookie, just use `res.clearCookie( name )`. - -That's about it. Send any questions or comments [here](http://twitter.com/jedschmidt). diff --git a/node_modules/twitter/node_modules/cookie/example/ex1.js b/node_modules/twitter/node_modules/cookie/example/ex1.js deleted file mode 100644 index 478c950..0000000 --- a/node_modules/twitter/node_modules/cookie/example/ex1.js +++ /dev/null @@ -1,14 +0,0 @@ -var http = require('http'), - cookie = require('../'); - -cookie.secret = "50m3thing-l0ng-@nd-r@nd0m-th@t-n0-0n3-will-gu355"; - -http.createServer(function (req, res) { - var rdm = req.getSecureCookie("rdm"); - if (!rdm) res.setSecureCookie("rdm", (Math.random()*1e9).toString(36)); - res.writeHead(200, {"Content-Type": "text/html"}); - if (rdm) res.write("Cookie has value: " + rdm); - res.end(); -}).listen(8080); - -console.log('Server running at http://127.0.0.1:8080/'); diff --git a/node_modules/twitter/node_modules/cookie/index.js b/node_modules/twitter/node_modules/cookie/index.js deleted file mode 100644 index ca39ea5..0000000 --- a/node_modules/twitter/node_modules/cookie/index.js +++ /dev/null @@ -1,161 +0,0 @@ -console.warn( - "This library has been deprecated.", - "Please use `npm install cookies` instead." -) - -var crypto = require('crypto'); -var Buffer = require('buffer').Buffer; - -function hex_hmac_sha1(data, key) { - var hmac = crypto.createHmac('sha1', key); - hmac.update(data); - return hmac.digest('hex'); -} - -var base64 = { - encode: function(str) { - return (new Buffer(str)).toString('base64'); - }, - decode: function(str) { - return (new Buffer(str, 'base64')).toString('utf8'); - } -}; - -var processCookie = exports.processCookie = function(name, value) { - var len, parts, expires, remoteSig, localSig; - - parts = value.replace(/\*/g, '=').split("|"); - - if ( parts.length !== 4 ) { - return null; - } - - len = parts[0]; - value = base64.decode( parts[1] ).substr(0, len); - expires = new Date( +parts[2] ); - remoteSig = parts[3]; - - if ( expires < Date.now() ) { - return null; - } - - localSig = hex_hmac_sha1( parts.slice( 0, 3 ).join("|"), cookieSecret() ); - - if ( localSig !== remoteSig ) { - throw new Error("invalid cookie signature: " + name); - } - - return value; -}; - - -var mutateHttp = function(http){ - http.IncomingMessage.prototype._parseCookies = function() { - var header = this.headers["cookie"] || "", - ret = {}; - - header.split(";").forEach( function( cookie ) { - var parts = cookie.split("="), - name = (parts[0] ? parts[0].trim() : ''), - value = (parts[1] ? parts[1].trim() : ''); - - ret[ name ] = value; - }); - return this.cookies = ret; - }; - - - http.IncomingMessage.prototype.getCookie = function( name ) { - var cookies = this.cookies || this._parseCookies(); - return cookies[ name ] || null; - }; - - http.IncomingMessage.prototype.getSecureCookie = function( name ) { - var value = this.getCookie( name ); - - if ( !value ) { - return null; - } - - return processCookie(name, value); - }; - - // this probably isn't kosher, but it's the best way to keep the interface sane. - var _writeHead = http.ServerResponse.prototype.writeHead; - var COOKIE_KEY = 'Set-Cookie', slice = Array.prototype.slice; - http.ServerResponse.prototype.writeHead = function () { - // Honor the passed args and method signature (see http.writeHead docs) - var args = slice.call(arguments), headers = args[args.length-1]; - if (!headers || typeof(headers) != 'object') { - // No header arg - create and append to args list - args.push(headers = []); - } - - // Merge cookie values - var prev = headers[COOKIE_KEY], cookies = this.cookies || []; - if (prev) cookies.push(prev); - if (cookies.length > 0) headers[COOKIE_KEY] = cookies.join(" "); - - // Invoke original writeHead() - _writeHead.apply(this, args); - }; - - http.ServerResponse.prototype.setCookie = function( name, value, options ) { - var cookies = this.cookies || ( this.cookies = [] ), - cookie = [ name, "=", value, ";" ]; - - options = options || {}; - - if ( options.expires ) - cookie.push( " expires=", (new Date(options.expires)).toUTCString(), ";" ); - - if ( options.path ) - cookie.push( " path=", options.path, ";" ); - - if ( options.domain ) - cookie.push( " domain=", options.domain, ";" ); - - if ( options.secure ) - cookie.push( " secure", ";" ); - - if ( options.httpOnly ) - cookie.push( " httponly" ); - - cookies.push( cookie.join("") ); - }; - - http.ServerResponse.prototype.generateCookieValue = function( value, options ) { - options = options || {}; - value = [ (value + '').length, base64.encode( value ), +options.expires ]; - var signature = hex_hmac_sha1( value.join("|"), cookieSecret() ); - - value.push( signature ); - value = value.join("|").replace(/=/g, '*'); - - return value; - }; - - http.ServerResponse.prototype.setSecureCookie = function( name, value, options ) { - options = options || {}; - if (value !== null && typeof value !== 'undefined') value = value.toString(); - else value = ''; - value = this.generateCookieValue(value, options); - this.setCookie( name, value, options ); - }; - - http.ServerResponse.prototype.clearCookie = function( name, options ) { - options = options || {}; - options.expires = new Date( Date.now() - 30 * 24 * 60 * 60 * 1000 ); - this.setCookie( name, "", options ); - }; -}; - -mutateHttp(require('http')); - - -function cookieSecret() { - if ( exports.secret ) - return exports.secret; - - return exports.secret = hex_hmac_sha1( Math.random(), Math.random() ); -} diff --git a/node_modules/twitter/node_modules/cookie/package.json b/node_modules/twitter/node_modules/cookie/package.json deleted file mode 100644 index fb11bc5..0000000 --- a/node_modules/twitter/node_modules/cookie/package.json +++ /dev/null @@ -1,6 +0,0 @@ -{ "name" : "cookie" -, "version" : "0.1.5" -, "description" : "A deprecated node.js library for handling secure cookies." -, "main" : "./index" -, "engines": [ "node" ] -} diff --git a/node_modules/twitter/node_modules/oauth/.gitignore b/node_modules/twitter/node_modules/oauth/.gitignore deleted file mode 100644 index 3c3629e..0000000 --- a/node_modules/twitter/node_modules/oauth/.gitignore +++ /dev/null @@ -1 +0,0 @@ -node_modules diff --git a/node_modules/twitter/node_modules/oauth/Makefile b/node_modules/twitter/node_modules/oauth/Makefile index ab4258a..be7c339 100644 --- a/node_modules/twitter/node_modules/oauth/Makefile +++ b/node_modules/twitter/node_modules/oauth/Makefile @@ -2,6 +2,6 @@ # Run all tests # test: - @@vows tests/* --spec + @@node_modules/.bin/vows tests/* --spec -.PHONY: test install \ No newline at end of file +.PHONY: test install diff --git a/node_modules/twitter/node_modules/oauth/Readme.md b/node_modules/twitter/node_modules/oauth/Readme.md index a59cbf6..613ffb5 100644 --- a/node_modules/twitter/node_modules/oauth/Readme.md +++ b/node_modules/twitter/node_modules/oauth/Readme.md @@ -4,36 +4,178 @@ A simple oauth API for node.js . This API allows users to authenticate against Tested against Twitter (http://twitter.com), term.ie (http://term.ie/oauth/example/), TwitPic, and Yahoo! -Also provides rudimentary OAuth2 support, tested against facebook connect and github. For more complete usage examples please take a look at connect-auth (http://github.com/ciaranj/connect-auth) +Also provides rudimentary OAuth2 support, tested against facebook, github, foursquare, google and Janrain. For more complete usage examples please take a look at connect-auth (http://github.com/ciaranj/connect-auth) +[![Clone in Koding](http://learn.koding.com/btn/clone_d.png)][koding] +[koding]: https://koding.com/Teamwork?import=https://github.com/ciaranj/node-oauth/archive/master.zip&c=git1 + +Installation +============== + + $ npm install oauth + + +Examples +========== + +To run examples/tests install Mocha `$ npm install -g mocha` and run `$ mocha you-file-name.js`: + +## OAuth1.0 + +```javascript +describe('OAuth1.0',function(){ + var OAuth = require('oauth'); + + it('tests trends Twitter API v1.1',function(done){ + var oauth = new OAuth.OAuth( + 'https://api.twitter.com/oauth/request_token', + 'https://api.twitter.com/oauth/access_token', + 'your application consumer key', + 'your application secret', + '1.0A', + null, + 'HMAC-SHA1' + ); + oauth.get( + 'https://api.twitter.com/1.1/trends/place.json?id=23424977', + 'your user token for this app', //test user token + 'your user secret for this app', //test user secret + function (e, data, res){ + if (e) console.error(e); + console.log(require('util').inspect(data)); + done(); + }); + }); +}); +``` + +## OAuth2.0 +```javascript +describe('OAuth2',function(){ + var OAuth = require('oauth'); + + it('gets bearer token', function(done){ + var OAuth2 = OAuth.OAuth2; + var twitterConsumerKey = 'your key'; + var twitterConsumerSecret = 'your secret'; + var oauth2 = new OAuth2(server.config.keys.twitter.consumerKey, + twitterConsumerSecret, + 'https://api.twitter.com/', + null, + 'oauth2/token', + null); + oauth2.getOAuthAccessToken( + '', + {'grant_type':'client_credentials'}, + function (e, access_token, refresh_token, results){ + console.log('bearer: ',access_token); + done(); + }); + }); +``` Change History ============== -* 0.9.5 - Allow usage of HTTP verbs other than GET for retrieving the access and request tokens (OAuth1) (Thanks to Raoul Millais) -* 0.9.4 - Support for OAuth providers that drop connections (don't send response lengths? [Google]) And change OAuth2 getOAuthAccessToken to POST rather than GET ( Possible Breaking change!!! ... re-tested against Google, Github, Facebook, FourSquare and Janrain and seems ok .. is closer to the spec (v20) ) -* 0.9.3 - Adds support for following 301 redirects (Thanks bdickason) -* 0.9.2 - Correct content length calculated for non-ascii post bodies (Thanks selead) -Allowed for configuration of the 'access token' name used when requesting protected resources (OAuth2) -* 0.9.1 - Added support for automatically following 302 redirects (Thanks neyric) Added support for OAuth Echo (Thanks Ryan LeFevre). Improved handling of 2xx responses (Thanks Neil Mansilla). -* 0.9.0 - Compatibility fixes to bring node-oauth up to speed with node.js 0.4x [thanks to Rasmus Andersson for starting the work ] -* 0.8.4 - Fixed issue #14 (Parameter ordering ignored encodings). Added support for repeated parameter names. Implements issue #15 (Use native SHA1 if available, 10x speed improvement!). Fixed issue #16 (Should use POST when requesting access tokens.). Fixed Issue #17 (OAuth2 spec compliance). Implemented enhancement #13 (Adds support for PUT & DELETE http verbs). Fixes issue #18 (Complex/Composite url arguments [thanks novemberborn]) -* 0.8.3 - Fixed an issue where the auth header code depended on the Array's toString method (Yohei Sasaki) Updated the getOAuthRequestToken method so we can access google's OAuth secured methods. Also re-implemented and fleshed out the test suite. -* 0.8.2 - The request returning methods will now write the POST body if provided (Chris Anderson), the code responsible for manipulating the headers is a bit safe now when working with other code (Paul McKellar) and tweaked the package.json to use index.js instead of main.js -* 0.8.1 - Added mechanism to get hold of a signed Node Request object, ready for attaching response listeners etc. (Perfect for streaming APIs) -* 0.8.0 - Standardised method capitalisation, the old getOauthAccessToken is now getOAuthAccessToken (Breaking change to existing code) -* 0.7.7 - Looks like non oauth_ parameters where appearing within the Authorization headers, which I believe to be incorrect. -* 0.7.6 - Added in oauth_verifier property to getAccessToken required for 1.0A -* 0.7.5 - Added in a main.js to simplify the require'ing of OAuth -* 0.7.4 - Minor change to add an error listener to the OAuth client (thanks troyk) -* 0.7.3 - OAuth 2 now sends a Content-Length Http header to keep nginx happy :) -* 0.7.2 - Fixes some broken unit tests! -* 0.7.0 - Introduces support for HTTPS end points and callback URLS for OAuth 1.0A and Oauth 2 (Please be aware that this was a breaking change to the constructor arguments order) - -Contributors -============ +* 0.9.12 + - OAuth1/2: Can now pass Buffer instance directly for PUTs+POSTs (thank you Evan Prodromou) + - OAuth1: Improve interoperability with libraries that mess with the prototype. (thank you Jose Ignacio Andres) + - OAuth2: Adds PUT support for OAuth2 (thank you Derek Brooks) + - OAuth1: Improves use_strict compatibility (thank you Ted Goddard) +* 0.9.11 + - OAuth2: No longer sends the type=webserver argument with the OAuth2 requests (thank you bendiy) + - OAuth2: Provides a default (and overrideable) User-Agent header (thanks to Andrew Martens & Daniel Mahlow) + - OAuth1: New followRedirects client option (true by default) (thanks to Pieter Joost van de Sande) + - OAuth1: Adds RSA-SHA1 support (thanks to Jeffrey D. Van Alstine & Michael Garvin & Andreas Knecht) +* 0.9.10 + - OAuth2: Addresses 2 issues that came in with 0.9.9, #129 & #125 (thank you José F. Romaniello) +* 0.9.9 + - OAuth1: Fix the mismatch between the output of querystring.stringify() and this._encodeData(). (thank you rolandboon) + - OAuth2: Adds Authorization Header and supports extra headers by default ( thanks to Brian Park) +* 0.9.8 + - OAuth1: Support overly-strict OAuth server's that require whitespace separating the Authorization Header parameters (e.g. 500px.com) (Thanks to Christian Schwarz) + - OAuth1: Fix incorrect double-encoding of PLAINTEXT OAuth connections (Thanks to Joe Rozner) + - OAuth1: Minor safety check added when checking hostnames. (Thanks to Garrick Cheung) +* 0.9.7 + - OAuth2: Pass back any extra response data for calls to getOAuthAccessToken (Thanks to Tang Bo Hao) + - OAuth2: Don't force a https request if given a http url (Thanks to Damien Mathieu) + - OAuth2: Supports specifying a grant-type of 'refresh-token' (Thanks to Luke Baker) +* 0.9.6 + - OAuth2: Support for 302 redirects (Thanks Patrick Negri). + - OAuth1/2: Some code tidying. ( Thanks to Raoul Millais ) +* 0.9.5 + - OAuth1: Allow usage of HTTP verbs other than GET for retrieving the access and request tokens (Thanks to Raoul Millais) +* 0.9.4 + - OAuth1/2: Support for OAuth providers that drop connections (don't send response lengths? [Google]) + - OAuth2: Change getOAuthAccessToken to POST rather than GET ( Possible Breaking change!!! ... re-tested against Google, Github, Facebook, FourSquare and Janrain and seems ok .. is closer to the spec (v20) ) +* 0.9.3 + - OAuth1: Adds support for following 301 redirects (Thanks bdickason) +* 0.9.2 + - OAuth1: Correct content length calculated for non-ascii post bodies (Thanks selead) + - OAuth1: Allowed for configuration of the 'access token' name used when requesting protected resources (OAuth2) +* 0.9.1 + - OAuth1: Added support for automatically following 302 redirects (Thanks neyric) + - OAuth1: Added support for OAuth Echo (Thanks Ryan LeFevre). + - OAuth1: Improved handling of 2xx responses (Thanks Neil Mansilla). +* 0.9.0 + - OAuth1/2: Compatibility fixes to bring node-oauth up to speed with node.js 0.4x [thanks to Rasmus Andersson for starting the work ] +* 0.8.4 + - OAuth1: Fixed issue #14 (Parameter ordering ignored encodings). + - OAuth1: Added support for repeated parameter names. + - OAuth1/2: Implements issue #15 (Use native SHA1 if available, 10x speed improvement!). + - OAuth2: Fixed issue #16 (Should use POST when requesting access tokens.). + - OAuth2: Fixed Issue #17 (OAuth2 spec compliance). + - OAuth1: Implemented enhancement #13 (Adds support for PUT & DELETE http verbs). + - OAuth1: Fixes issue #18 (Complex/Composite url arguments [thanks novemberborn]) +* 0.8.3 + - OAuth1: Fixed an issue where the auth header code depended on the Array's toString method (Yohei Sasaki) Updated the getOAuthRequestToken method so we can access google's OAuth secured methods. Also re-implemented and fleshed out the test suite. +* 0.8.2 + - OAuth1: The request returning methods will now write the POST body if provided (Chris Anderson), the code responsible for manipulating the headers is a bit safe now when working with other code (Paul McKellar) + - Package: Tweaked the package.json to use index.js instead of main.js +* 0.8.1 + - OAuth1: Added mechanism to get hold of a signed Node Request object, ready for attaching response listeners etc. (Perfect for streaming APIs) +* 0.8.0 + - OAuth1: Standardised method capitalisation, the old getOauthAccessToken is now getOAuthAccessToken (Breaking change to existing code) +* 0.7.7 + - OAuth1: Looks like non oauth_ parameters where appearing within the Authorization headers, which I believe to be incorrect. +* 0.7.6 + - OAuth1: Added in oauth_verifier property to getAccessToken required for 1.0A +* 0.7.5 + - Package: Added in a main.js to simplify the require'ing of OAuth +* 0.7.4 + - OAuth1: Minor change to add an error listener to the OAuth client (thanks troyk) +* 0.7.3 + - OAuth2: Now sends a Content-Length Http header to keep nginx happy :) +* 0.7.2 + - OAuth1: Fixes some broken unit tests! +* 0.7.0 + - OAuth1/2: Introduces support for HTTPS end points and callback URLS for OAuth 1.0A and Oauth 2 (Please be aware that this was a breaking change to the constructor arguments order) + +Contributors (In no particular order) +===================================== +* Evan Prodromou +* Jose Ignacio Andres +* Ted Goddard +* Derek Brooks * Ciaran Jessup - ciaranj@gmail.com * Mark Wubben - http://equalmedia.com/ * Ryan LeFevre - http://meltingice.net * Raoul Millais +* Patrick Negri - http://github.com/pnegri +* Tang Bo Hao - http://github.com/btspoony +* Damien Mathieu - http://42.dmathieu.com +* Luke Baker - http://github.com/lukebaker +* Christian Schwarz - http://github.com/chrischw/ +* Joe Rozer - http://www.deadbytes.net +* Garrick Cheung - http://www.garrickcheung.com/ +* rolandboon - http://rolandboon.com +* Brian Park - http://github.com/yaru22 +* José F. Romaniello - http://github.com/jfromaniello +* bendiy - https://github.com/bendiy +* Andrew Martins - http://www.andrewmartens.com +* Daniel Mahlow - https://github.com/dmahlow +* Pieter Joost van de Sande - https://github.com/pjvds +* Jeffrey D. Van Alstine +* Michael Garvin +* Andreas Knecht diff --git a/node_modules/twitter/node_modules/oauth/debian/changelog b/node_modules/twitter/node_modules/oauth/debian/changelog deleted file mode 100644 index 68afda1..0000000 --- a/node_modules/twitter/node_modules/oauth/debian/changelog +++ /dev/null @@ -1,26 +0,0 @@ -nodejs-oauth (0.8.2-0sg4) UNRELEASED; urgency=low - - * UNRELEASED - - -- SimpleGeo Nerds Mon, 15 Nov 2010 19:30:19 +0000 - -nodejs-oauth (0.8.2-0sg2) UNRELEASED; urgency=low - - [ Wade Simmons ] - * update copyright - - [ SimpleGeo Nerds ] - - -- SimpleGeo Nerds Thu, 14 Oct 2010 17:51:51 +0000 - -nodejs-oauth (0.8.2-0sg1) UNRELEASED; urgency=low - - * UNRELEASED - - -- SimpleGeo Nerds Wed, 13 Oct 2010 23:19:29 +0000 - -nodejs-oauth (0.8.2-0sg0) unstable; urgency=low - - * Debianized - - -- Wade Simmons Wed, 13 Oct 2010 17:08:18 -0600 diff --git a/node_modules/twitter/node_modules/oauth/debian/compat b/node_modules/twitter/node_modules/oauth/debian/compat deleted file mode 100644 index 7ed6ff8..0000000 --- a/node_modules/twitter/node_modules/oauth/debian/compat +++ /dev/null @@ -1 +0,0 @@ -5 diff --git a/node_modules/twitter/node_modules/oauth/debian/control b/node_modules/twitter/node_modules/oauth/debian/control deleted file mode 100644 index 11cd0c1..0000000 --- a/node_modules/twitter/node_modules/oauth/debian/control +++ /dev/null @@ -1,13 +0,0 @@ -Source: nodejs-oauth -Section: misc -Priority: extra -Uploaders: Wade Simmons -Maintainer: SimpleGeo Nerds -build-Depends: cdbs, debhelper (>= 7) -Standards-Version: 3.9.1 - -Package: nodejs-oauth -Depends: nodejs (>= 0.2.3), ${misc:Depends} -Architecture: all -Description: node-oauth - http://github.com/ciaranj/node-oauth diff --git a/node_modules/twitter/node_modules/oauth/debian/copyright b/node_modules/twitter/node_modules/oauth/debian/copyright deleted file mode 100644 index 8f0eb29..0000000 --- a/node_modules/twitter/node_modules/oauth/debian/copyright +++ /dev/null @@ -1,9 +0,0 @@ -This package was debianised by Wade Simmons - -The upstream repo is: - http://github.com/ciaranj/node-oauth - MIT license - -The Debian packaging is - Copyright 2010, SimpleGeo, Inc. - MIT license diff --git a/node_modules/twitter/node_modules/oauth/debian/dirs b/node_modules/twitter/node_modules/oauth/debian/dirs deleted file mode 100644 index 81ecf44..0000000 --- a/node_modules/twitter/node_modules/oauth/debian/dirs +++ /dev/null @@ -1 +0,0 @@ -usr/lib/nodejs/oauth diff --git a/node_modules/twitter/node_modules/oauth/debian/install b/node_modules/twitter/node_modules/oauth/debian/install deleted file mode 100644 index 2af6cc3..0000000 --- a/node_modules/twitter/node_modules/oauth/debian/install +++ /dev/null @@ -1,2 +0,0 @@ -index.js usr/lib/nodejs/oauth -lib usr/lib/nodejs/oauth diff --git a/node_modules/twitter/node_modules/oauth/debian/rules b/node_modules/twitter/node_modules/oauth/debian/rules deleted file mode 100755 index e6192f6..0000000 --- a/node_modules/twitter/node_modules/oauth/debian/rules +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/make -f - -include /usr/share/cdbs/1/rules/debhelper.mk diff --git a/node_modules/twitter/node_modules/oauth/debian/source/format b/node_modules/twitter/node_modules/oauth/debian/source/format deleted file mode 100644 index 163aaf8..0000000 --- a/node_modules/twitter/node_modules/oauth/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (quilt) diff --git a/node_modules/twitter/node_modules/oauth/examples/term.ie.oauth-HMAC-SHA1.js b/node_modules/twitter/node_modules/oauth/examples/term.ie.oauth-HMAC-SHA1.js index eb02692..91af05d 100644 --- a/node_modules/twitter/node_modules/oauth/examples/term.ie.oauth-HMAC-SHA1.js +++ b/node_modules/twitter/node_modules/oauth/examples/term.ie.oauth-HMAC-SHA1.js @@ -1,4 +1,4 @@ -var sys= require('sys') +var util= require('util') var OAuth= require('../lib/oauth').OAuth; @@ -11,21 +11,21 @@ var oa= new OAuth("http://term.ie/oauth/example/request_token.php", "HMAC-SHA1") oa.getOAuthRequestToken(function(error, oauth_token, oauth_token_secret, results){ - if(error) sys.puts('error :' + error) + if(error) util.puts('error :' + error) else { - sys.puts('oauth_token :' + oauth_token) - sys.puts('oauth_token_secret :' + oauth_token_secret) - sys.puts('requestoken results :' + sys.inspect(results)) - sys.puts("Requesting access token") + util.puts('oauth_token :' + oauth_token) + util.puts('oauth_token_secret :' + oauth_token_secret) + util.puts('requestoken results :' + util.inspect(results)) + util.puts("Requesting access token") oa.getOAuthAccessToken(oauth_token, oauth_token_secret, function(error, oauth_access_token, oauth_access_token_secret, results2) { - sys.puts('oauth_access_token :' + oauth_access_token) - sys.puts('oauth_token_secret :' + oauth_access_token_secret) - sys.puts('accesstoken results :' + sys.inspect(results2)) - sys.puts("Requesting access token") + util.puts('oauth_access_token :' + oauth_access_token) + util.puts('oauth_token_secret :' + oauth_access_token_secret) + util.puts('accesstoken results :' + util.inspect(results2)) + util.puts("Requesting access token") var data= ""; oa.getProtectedResource("http://term.ie/oauth/example/echo_api.php?foo=bar&too=roo", "GET", oauth_access_token, oauth_access_token_secret, function (error, data, response) { - sys.puts(data); + util.puts(data); }); }); } -}) \ No newline at end of file +}) diff --git a/node_modules/twitter/node_modules/oauth/examples/term.ie.oauth-PLAINTEXT.js b/node_modules/twitter/node_modules/oauth/examples/term.ie.oauth-PLAINTEXT.js deleted file mode 100644 index 12c583a..0000000 --- a/node_modules/twitter/node_modules/oauth/examples/term.ie.oauth-PLAINTEXT.js +++ /dev/null @@ -1,34 +0,0 @@ -var sys= require('sys') - -var OAuth= require('../lib/oauth').OAuth; - -var oa = new OAuth("http://term.ie/oauth/example/request_token.php?foo=bar", - "http://term.ie/oauth/example/access_token.php", - "key", - "secret", - "1.0", - null, - "PLAINTEXT") - -oa.getOAuthRequestToken(function(error, oauth_token, oauth_token_secret, results){ - if (error) return console.log('error :' + error) - console.log('oauth_token :' + oauth_token) - console.log('oauth_token_secret :' + oauth_token_secret) - console.log('requestoken results :', results) - console.log("Requesting access token") - oa.getOAuthAccessToken(oauth_token, oauth_token_secret, - function(error, oauth_access_token, - oauth_access_token_secret, results2) { - console.log('oauth_access_token :' + oauth_access_token) - console.log('oauth_token_secret :' + oauth_access_token_secret) - console.log('accesstoken results :', results2) - console.log("Requesting access token") - var data= ""; - oa.getProtectedResource( - "http://term.ie/oauth/example/echo_api.php?foo=bar&too=roo", "GET", - oauth_access_token, oauth_access_token_secret, - function (error, data, response) { - console.log(data); - }); - }); -}) \ No newline at end of file diff --git a/node_modules/twitter/node_modules/oauth/examples/twitter-test.js b/node_modules/twitter/node_modules/oauth/examples/twitter-test.js deleted file mode 100644 index bfd4b10..0000000 --- a/node_modules/twitter/node_modules/oauth/examples/twitter-test.js +++ /dev/null @@ -1,34 +0,0 @@ -var sys= require('sys'); -var OAuth= require('../lib/oauth').OAuth; -oa= new OAuth("https://twitter.com/oauth/request_token", - "https://twitter.com/oauth/access_token", - "JiYmll7CX3AXDgasnnIDeg", "mWPBRK5kG2Tkthuf5zRV1jYWOEwnjI6xs3QVRqOOg", - "1.0A", "http://localhost:3000/oauth/callback", "HMAC-SHA1"); - -var delim = /\n*\r\n*/; -var buffer= ""; - -//var filterString= require('querystring').escape(process.argv[2]); -var filterString= require('querystring').escape("social or network"); -var request= oa.post("http://stream.twitter.com/1/statuses/filter.json?track="+ filterString, - "23186482-ZXEosOnO34TIzAAMEVMilrXcHezMF4odlDwvKNyA", - "PnNN2GWYlfNCyhN6dAiMLQdvvDLy67dpaALies"); -request.addListener('response', function (response) { - response.setEncoding('utf8'); - response.addListener('data', function (chunk) { - buffer += chunk; - var parts= buffer.split(delim); - var len = parts.length; - if( len >1 ) { - buffer = parts[len-1]; - for(var i=0, end = len -1; i< end; ++i) { - var entry = parts[i]; - if( entry !== "" ) { - var obj= JSON.parse(entry); - console.log("@"+ obj.user.screen_name +" says " + obj.text); - } - } - } - }); -}); -request.end(); \ No newline at end of file diff --git a/node_modules/twitter/node_modules/oauth/fapp.js b/node_modules/twitter/node_modules/oauth/fapp.js deleted file mode 100644 index d05a94e..0000000 --- a/node_modules/twitter/node_modules/oauth/fapp.js +++ /dev/null @@ -1,27 +0,0 @@ -var http = require('http') - , OAuth= require('./index').OAuth - , url = require('url') - , consumerKey= "RuN9ovM7vvXyOO1N6DmhsA" - , consumerSecret= "qpUPDJJasO5G2jZenK3m7t7pAcA9ZuyUv8WsGnonJo"; - -var oAuth= new OAuth("http://twitter.com/oauth/request_token", - "http://twitter.com/oauth/access_token", - consumerKey, consumerSecret, - "1.0a", "http://redirect_callback_url.com", "HMAC-SHA1"); - -http.createServer(function (req, res) { - var urlp= url.parse(req.url, true); - if( urlp.query && urlp.query.oauth_verifier ) { - res.writeHead(200, {'Content-Type': 'text/plain'}); - res.end('Verification callback: ' + urlp.query.oauth_verifier +'\n'); - } - else { - oAuth.getOAuthRequestToken(function(error, oauth_token, oauth_token_secret, oauth_authorize_url, additionalParameters ) { - console.log( error ); - res.writeHead(301, { - 'Location': "http://twitter.com/oauth/authenticate?oauth_token=" + oauth_token - }); - res.end(); - }); - } -}).listen(80, "127.0.0.1"); diff --git a/node_modules/twitter/node_modules/oauth/google-test.js b/node_modules/twitter/node_modules/oauth/google-test.js deleted file mode 100644 index dfd7fe5..0000000 --- a/node_modules/twitter/node_modules/oauth/google-test.js +++ /dev/null @@ -1,29 +0,0 @@ -//var OAuth= require('./lib/oauth').OAuth; -var sys= require('sys'); -var OAuth= require('./lib/oauth').OAuth; - -oa= new OAuth("https://www.google.com/accounts/OAuthGetRequestToken", - "https://www.google.com/accounts/OAuthAuthorizeToken", - "anonymous", "anonymous", - "1.0A", "http://localhost:3000/oauth/callback", "HMAC-SHA1"); - -oa.getOAuthRequestToken({"scope":"http://www.google.com/calendar/feeds"},function(error, oauth_token, oauth_token_secret, results){ - if(error) sys.puts('error :' + JSON.stringify(error)) - else { - sys.puts('oauth_token: ' + oauth_token) - sys.puts('oauth_token_secret: ' + oauth_token_secret) - sys.puts('requestoken results: ' + sys.inspect(results)) - sys.puts("Requesting access token") -/* oa.getOAuthAccessToken(oauth_token, oauth_token_secret, 'verifier', function(error, oauth_access_token, oauth_access_token_secret, results2) { - sys.puts('oauth_access_token: ' + oauth_access_token) - sys.puts('oauth_token_secret: ' + oauth_access_token_secret) - sys.puts('accesstoken results: ' + sys.inspect(results2)) - sys.puts("Requesting secure schznit") - var data= ""; - oa.getProtectedResource("http://localhost:3000/fetch/unicorns?foo=bar&too=roo", "GET", oauth_access_token, oauth_access_token_secret, function (error, data, response) { - sys.puts(sys.inspect(error)); - sys.puts(data); - }); - }); */ - } -}) \ No newline at end of file diff --git a/node_modules/twitter/node_modules/oauth/lib/_utils.js b/node_modules/twitter/node_modules/oauth/lib/_utils.js index 1efd336..69fc300 100644 --- a/node_modules/twitter/node_modules/oauth/lib/_utils.js +++ b/node_modules/twitter/node_modules/oauth/lib/_utils.js @@ -1,4 +1,4 @@ // Returns true if this is a host that closes *before* it ends?!?! module.exports.isAnEarlyCloseHost= function( hostName ) { - return hostName.match(".*google.com$") + return hostName && hostName.match(".*google(apis)?.com$") } \ No newline at end of file diff --git a/node_modules/twitter/node_modules/oauth/lib/oauth.js b/node_modules/twitter/node_modules/oauth/lib/oauth.js index 6283b1e..50dccf9 100644 --- a/node_modules/twitter/node_modules/oauth/lib/oauth.js +++ b/node_modules/twitter/node_modules/oauth/lib/oauth.js @@ -13,6 +13,9 @@ exports.OAuth= function(requestUrl, accessUrl, consumerKey, consumerSecret, vers this._accessUrl= accessUrl; this._consumerKey= consumerKey; this._consumerSecret= this._encodeData( consumerSecret ); + if (signatureMethod == "RSA-SHA1") { + this._privateKey = consumerSecret; + } this._version= version; if( authorize_callback === undefined ) { this._authorize_callback= "oob"; @@ -21,7 +24,7 @@ exports.OAuth= function(requestUrl, accessUrl, consumerKey, consumerSecret, vers this._authorize_callback= authorize_callback; } - if( signatureMethod != "PLAINTEXT" && signatureMethod != "HMAC-SHA1") + if( signatureMethod != "PLAINTEXT" && signatureMethod != "HMAC-SHA1" && signatureMethod != "RSA-SHA1") throw new Error("Un-supported signature method: " + signatureMethod ) this._signatureMethod= signatureMethod; this._nonceSize= nonceSize || 32; @@ -29,7 +32,9 @@ exports.OAuth= function(requestUrl, accessUrl, consumerKey, consumerSecret, vers "Connection" : "close", "User-Agent" : "Node authentication"} this._clientOptions= this._defaultClientOptions= {"requestTokenHttpMethod": "POST", - "accessTokenHttpMethod": "POST"}; + "accessTokenHttpMethod": "POST", + "followRedirects": true}; + this._oauthParameterSeperator = ","; }; exports.OAuthEcho= function(realm, verify_credentials, consumerKey, consumerSecret, version, signatureMethod, nonceSize, customHeaders) { @@ -39,15 +44,19 @@ exports.OAuthEcho= function(realm, verify_credentials, consumerKey, consumerSecr this._verifyCredentials = verify_credentials; this._consumerKey= consumerKey; this._consumerSecret= this._encodeData( consumerSecret ); + if (signatureMethod == "RSA-SHA1") { + this._privateKey = consumerSecret; + } this._version= version; - if( signatureMethod != "PLAINTEXT" && signatureMethod != "HMAC-SHA1") + if( signatureMethod != "PLAINTEXT" && signatureMethod != "HMAC-SHA1" && signatureMethod != "RSA-SHA1") throw new Error("Un-supported signature method: " + signatureMethod ); this._signatureMethod= signatureMethod; this._nonceSize= nonceSize || 32; this._headers= customHeaders || {"Accept" : "*/*", "Connection" : "close", "User-Agent" : "Node authentication"}; + this._oauthParameterSeperator = ","; } exports.OAuthEcho.prototype = exports.OAuth.prototype; @@ -84,7 +93,7 @@ exports.OAuth.prototype._getSignature= function(method, url, parameters, tokenSe exports.OAuth.prototype._normalizeUrl= function(url) { var parsedUrl= URL.parse(url, true) var port =""; - if( parsedUrl.port ) { + if( parsedUrl.port ) { if( (parsedUrl.protocol == "http:" && parsedUrl.port != "80" ) || (parsedUrl.protocol == "https:" && parsedUrl.port != "443") ) { port= ":" + parsedUrl.port; @@ -92,7 +101,7 @@ exports.OAuth.prototype._normalizeUrl= function(url) { } if( !parsedUrl.pathname || parsedUrl.pathname == "" ) parsedUrl.pathname ="/"; - + return parsedUrl.protocol + "//" + parsedUrl.hostname + port + parsedUrl.pathname; } @@ -118,11 +127,11 @@ exports.OAuth.prototype._buildAuthorizationHeaders= function(orderedParameters) // Whilst the all the parameters should be included within the signature, only the oauth_ arguments // should appear within the authorization header. if( this._isParameterNameAnOAuthParameter(orderedParameters[i][0]) ) { - authHeader+= "" + this._encodeData(orderedParameters[i][0])+"=\""+ this._encodeData(orderedParameters[i][1])+"\","; + authHeader+= "" + this._encodeData(orderedParameters[i][0])+"=\""+ this._encodeData(orderedParameters[i][1])+"\""+ this._oauthParameterSeperator; } } - authHeader= authHeader.substring(0, authHeader.length-1); + authHeader= authHeader.substring(0, authHeader.length-this._oauthParameterSeperator.length); return authHeader; } @@ -131,6 +140,7 @@ exports.OAuth.prototype._buildAuthorizationHeaders= function(orderedParameters) exports.OAuth.prototype._makeArrayOfArgumentsHash= function(argumentsHash) { var argument_pairs= []; for(var key in argumentsHash ) { + if (argumentsHash.hasOwnProperty(key)) { var value= argumentsHash[key]; if( Array.isArray(value) ) { for(var i=0;i= 200 && response.statusCode <= 299 ) { callback(null, data, response); } else { // Follow 301 or 302 redirects with Location HTTP header - if((response.statusCode == 301 || response.statusCode == 302) && response.headers && response.headers.location) { + if((response.statusCode == 301 || response.statusCode == 302) && clientOptions.followRedirects && response.headers && response.headers.location) { self._performSecureRequest( oauth_token, oauth_token_secret, method, response.headers.location, extra_params, post_body, post_content_type, callback); } else { @@ -383,12 +414,14 @@ exports.OAuth.prototype._performSecureRequest= function( oauth_token, oauth_toke } }); }); - + request.on("error", function(err) { - callbackCalled= true; - callback( err ) + if(!callbackCalled) { + callbackCalled= true; + callback( err ) + } }); - + if( (method == "POST" || method =="PUT") && post_body != null && post_body != "" ) { request.write(post_body); } @@ -400,7 +433,7 @@ exports.OAuth.prototype._performSecureRequest= function( oauth_token, oauth_toke } return request; } - + return; } @@ -427,7 +460,7 @@ exports.OAuth.prototype.getOAuthAccessToken= function(oauth_token, oauth_token_s } else { extraParams.oauth_verifier= oauth_verifier; } - + this._performSecureRequest( oauth_token, oauth_token_secret, this._clientOptions.accessTokenHttpMethod, this._accessUrl, extraParams, null, null, function(error, data, response) { if( error ) callback(error); else { @@ -460,14 +493,14 @@ exports.OAuth.prototype._putOrPost= function(method, url, oauth_token, oauth_tok callback= post_content_type; post_content_type= null; } - if( typeof post_body != "string" ) { + if ( typeof post_body != "string" && !Buffer.isBuffer(post_body) ) { post_content_type= "application/x-www-form-urlencoded" extra_params= post_body; post_body= null; } return this._performSecureRequest( oauth_token, oauth_token_secret, method, url, extra_params, post_body, post_content_type, callback ); } - + exports.OAuth.prototype.put= function(url, oauth_token, oauth_token_secret, post_body, post_content_type, callback) { return this._putOrPost("PUT", url, oauth_token, oauth_token_secret, post_body, post_content_type, callback); @@ -483,7 +516,7 @@ exports.OAuth.prototype.post= function(url, oauth_token, oauth_token_secret, pos * * The callback should expect a function of the following form: * - * function(err, token, token_secret, parsedQueryString) {} + * function(err, token, token_secret, parsedQueryString) {} * * This method has optional parameters so can be called in the following 2 ways: * @@ -502,7 +535,7 @@ exports.OAuth.prototype.getOAuthRequestToken= function( extraParams, callback ) callback = extraParams; extraParams = {}; } - // Callbacks are 1.0A related + // Callbacks are 1.0A related if( this._authorize_callback ) { extraParams["oauth_callback"]= this._authorize_callback; } @@ -529,12 +562,12 @@ exports.OAuth.prototype.signUrl= function(url, oauth_token, oauth_token_secret, var orderedParameters= this._prepareParameters(oauth_token, oauth_token_secret, method, url, {}); var parsedUrl= URL.parse( url, false ); - var query=""; + var query=""; for( var i= 0 ; i < orderedParameters.length; i++) { query+= orderedParameters[i][0]+"="+ this._encodeData(orderedParameters[i][1]) + "&"; } query= query.substring(0, query.length-1); - + return parsedUrl.protocol + "//"+ parsedUrl.host + parsedUrl.pathname + "?" + query; }; diff --git a/node_modules/twitter/node_modules/oauth/lib/oauth.js.orig b/node_modules/twitter/node_modules/oauth/lib/oauth.js.orig deleted file mode 100644 index 685615d..0000000 --- a/node_modules/twitter/node_modules/oauth/lib/oauth.js.orig +++ /dev/null @@ -1,391 +0,0 @@ -var crypto= require('crypto'), - sha1= require('./sha1'), - http= require('http'), - URL= require('url'), - querystring= require('querystring'); - -exports.OAuth= function(requestUrl, accessUrl, consumerKey, consumerSecret, version, authorize_callback, signatureMethod, nonceSize, customHeaders) { - this._requestUrl= requestUrl; - this._accessUrl= accessUrl; - this._consumerKey= consumerKey; - this._consumerSecret= this._encodeData( consumerSecret ); - this._version= version; - if( authorize_callback === undefined ) { - this._authorize_callback= "oob"; - } - else { - this._authorize_callback= authorize_callback; - } - - if( signatureMethod != "PLAINTEXT" && signatureMethod != "HMAC-SHA1") - throw new Error("Un-supported signature method: " + signatureMethod ) - this._signatureMethod= signatureMethod; - this._nonceSize= nonceSize || 32; - this._headers= customHeaders || {"Accept" : "*/*", - "Connection" : "close", - "User-Agent" : "Node authentication"} -}; - -exports.OAuth.prototype._getTimestamp= function() { - return Math.floor( (new Date()).getTime() / 1000 ); -} - -exports.OAuth.prototype._encodeData= function(toEncode){ - if( toEncode == null || toEncode == "" ) return "" - else { - var result= encodeURIComponent(toEncode); - // Fix the mismatch between OAuth's RFC3986's and Javascript's beliefs in what is right and wrong ;) - return result.replace(/\!/g, "%21") - .replace(/\'/g, "%27") - .replace(/\(/g, "%28") - .replace(/\)/g, "%29") - .replace(/\*/g, "%2A"); - } -} - -exports.OAuth.prototype._decodeData= function(toDecode) { - if( toDecode != null ) { - toDecode = toDecode.replace(/\+/g, " "); - } - return decodeURIComponent( toDecode); -} - -exports.OAuth.prototype._getSignature= function(method, url, parameters, tokenSecret) { - var signatureBase= this._createSignatureBase(method, url, parameters); - return this._createSignature( signatureBase, tokenSecret ); -} - -exports.OAuth.prototype._normalizeUrl= function(url) { - var parsedUrl= URL.parse(url, true) - var port =""; - if( parsedUrl.port ) { - if( (parsedUrl.protocol == "http:" && parsedUrl.port != "80" ) || - (parsedUrl.protocol == "https:" && parsedUrl.port != "443") ) { - port= ":" + parsedUrl.port; - } - } - - if( !parsedUrl.pathname || parsedUrl.pathname == "" ) parsedUrl.pathname ="/"; - - return parsedUrl.protocol + "//" + parsedUrl.hostname + port + parsedUrl.pathname; -} - -// build the OAuth request authorization header -exports.OAuth.prototype._buildAuthorizationHeaders= function(orderedParameters) { - var authHeader="OAuth "; - for( var i= 0 ; i < orderedParameters.length; i++) { - // Whilst the all the parameters should be included within the signature, only the oauth_ arguments - // should appear within the authorization header. - var m = orderedParameters[i][0].match('^oauth_'); - if( m && m[0] === "oauth_") { - authHeader+= this._encodeData(orderedParameters[i][0])+"=\""+ this._encodeData(orderedParameters[i][1])+"\","; - } - } - authHeader= authHeader.substring(0, authHeader.length-1); - return authHeader; -} - -// Takes a literal in, then returns a sorted array -exports.OAuth.prototype._sortRequestParams= function(argumentsHash) { - var argument_pairs= []; - for(var key in argumentsHash ) { - argument_pairs[argument_pairs.length]= [key, argumentsHash[key]]; - } - // Sort by name, then value. - argument_pairs.sort(function(a,b) { - if ( a[0]== b[0] ) { - return a[1] < b[1] ? -1 : 1; - } - else return a[0] < b[0] ? -1 : 1; - }); - - return argument_pairs; -} - -exports.OAuth.prototype._normaliseRequestParams= function(arguments) { - var argument_pairs= this._sortRequestParams( arguments ); - var args= ""; - for(var i=0;i>>>>>> bd54d3f89951f438b41a3e5f56e97145d597d030 - headers["Host"] = parsedUrl.host - - for( var key in this._headers ) { - if (this._headers.hasOwnProperty(key)) { - headers[key]= this._headers[key]; - } - } - - headers["Content-length"]= post_body ? post_body.length : 0; //Probably going to fail if not posting ascii - headers["Content-Type"]= post_content_type; - - var path; - if( !parsedUrl.pathname || parsedUrl.pathname == "" ) parsedUrl.pathname ="/"; - if( parsedUrl.query ) path= parsedUrl.pathname + "?"+ parsedUrl.query ; - else path= parsedUrl.pathname; - - var request = oauthProvider.request(method, path , headers); - if( callback ) { - var data=""; - var self= this; - request.addListener('response', function (response) { - response.setEncoding('utf8'); - response.addListener('data', function (chunk) { - data+=chunk; - }); - response.addListener('end', function () { - if( response.statusCode != 200 ) { - callback({ statusCode: response.statusCode, data: data }); - } else { - callback(null, data, response); - } - }); - }); - - request.socket.addListener("error",callback); - if( method == "POST" && post_body != null && post_body != "" ) { - request.write(post_body); - } - request.end(); - } - else { - if( method == "POST" && post_body != null && post_body != "" ) { - request.write(post_body); - } - return request; - } - - return; -} - -exports.OAuth.prototype.getOAuthAccessToken= function(oauth_token, oauth_token_secret, oauth_verifier, callback) { - var extraParams= {}; - if( typeof oauth_verifier == "function" ) { - callback= oauth_verifier; - } else { - extraParams.oauth_verifier= oauth_verifier; - } - - this._performSecureRequest( oauth_token, oauth_token_secret, "GET", this._accessUrl, extraParams, "", null, function(error, data, response) { - if( error ) callback(error); - else { - var results= querystring.parse( data ); - var oauth_access_token= results["oauth_token"]; - delete results["oauth_token"]; - var oauth_access_token_secret= results["oauth_token_secret"]; - delete results["oauth_token_secret"]; - callback(null, oauth_access_token, oauth_access_token_secret, results ); - } - }) -} - -// Deprecated -exports.OAuth.prototype.getProtectedResource= function(url, method, oauth_token, oauth_token_secret, callback) { - this._performSecureRequest( oauth_token, oauth_token_secret, method, url, null, "", null, callback ); -} - -exports.OAuth.prototype.get= function(url, oauth_token, oauth_token_secret, callback) { - return this._performSecureRequest( oauth_token, oauth_token_secret, "GET", url, null, "", null, callback ); -} - -exports.OAuth.prototype.post= function(url, oauth_token, oauth_token_secret, post_body, post_content_type, callback) { - var extra_params= null; - if( typeof post_content_type == "function" ) { - callback= post_content_type; - post_content_type= null; - } - if( typeof post_body != "string" ) { - post_content_type= "application/x-www-form-urlencoded" - extra_params= post_body; - post_body= querystring.stringify(post_body); - } - return this._performSecureRequest( oauth_token, oauth_token_secret, "POST", url, extra_params, post_body, post_content_type, callback ); -} - -exports.OAuth.prototype.getOAuthRequestToken= function(extraParams, callback) { - if( typeof extraParams == "function" ){ - callback = extraParams; - extraParams = {}; - } - - // Callbacks are 1.0A related - if( this._authorize_callback ) { - extraParams["oauth_callback"]= this._authorize_callback; - } - this._performSecureRequest( null, null, "POST", this._requestUrl, extraParams, "", null, function(error, data, response) { - if( error ) callback(error); - else { - var results= querystring.parse(data); - - var oauth_token= results["oauth_token"]; - var oauth_token_secret= results["oauth_token_secret"]; - delete results["oauth_token"]; - delete results["oauth_token_secret"]; - callback(null, oauth_token, oauth_token_secret, results ); - } - }); -} - -exports.OAuth.prototype.signUrl= function(url, oauth_token, oauth_token_secret, method) { - var collectedParameters= { - "oauth_timestamp": this._getTimestamp(), - "oauth_nonce": this._getNonce(this._nonceSize), - "oauth_version": this._version, - "oauth_signature_method": this._signatureMethod, - "oauth_consumer_key": this._consumerKey - }; - - if( oauth_token ) { - collectedParameters["oauth_token"]= oauth_token; - } - if( method === undefined ) { - var method= "GET"; - } - - var parsedUrl= URL.parse( url, false ); - if( parsedUrl.protocol == "http:" && !parsedUrl.port ) parsedUrl.port= 80; - if( parsedUrl.protocol == "https:" && !parsedUrl.port ) parsedUrl.port= 443; - - if( parsedUrl.query ) { - var queryParams= querystring.parse(parsedUrl.query); - for(var key in queryParams ) { - collectedParameters[key]= queryParams[key]; - } - } - - var sig= this._getSignature( method, url, this._normaliseRequestParams(collectedParameters), oauth_token_secret); - var orderedParameters= this._sortRequestParams( collectedParameters ); - orderedParameters[orderedParameters.length]= ["oauth_signature", sig]; - - var query=""; - for( var i= 0 ; i < orderedParameters.length; i++) { - query+= orderedParameters[i][0]+"="+ this._encodeData(orderedParameters[i][1]) + "&"; - } - query= query.substring(0, query.length-1); - - return parsedUrl.protocol + "//"+ parsedUrl.host + parsedUrl.pathname + "?" + query; -}; - - - - diff --git a/node_modules/twitter/node_modules/oauth/lib/oauth2.js b/node_modules/twitter/node_modules/oauth/lib/oauth2.js index 373f135..e2505df 100644 --- a/node_modules/twitter/node_modules/oauth/lib/oauth2.js +++ b/node_modules/twitter/node_modules/oauth/lib/oauth2.js @@ -1,16 +1,20 @@ var querystring= require('querystring'), crypto= require('crypto'), https= require('https'), + http= require('http'), URL= require('url'), OAuthUtils= require('./_utils'); -exports.OAuth2= function(clientId, clientSecret, baseSite, authorizePath, accessTokenPath) { +exports.OAuth2= function(clientId, clientSecret, baseSite, authorizePath, accessTokenPath, customHeaders) { this._clientId= clientId; - this._clientSecret= clientSecret; + this._clientSecret= clientSecret; this._baseSite= baseSite; this._authorizeUrl= authorizePath || "/oauth/authorize"; this._accessTokenUrl= accessTokenPath || "/oauth/access_token"; this._accessTokenName= "access_token"; + this._authMethod= "Bearer"; + this._customHeaders = customHeaders || {}; + this._useAuthorizationHeaderForGET= false; } // This 'hack' method is required for sites that don't use @@ -22,17 +26,53 @@ exports.OAuth2.prototype.setAccessTokenName= function ( name ) { this._accessTokenName= name; } +// Sets the authorization method for Authorization header. +// e.g. Authorization: Bearer # "Bearer" is the authorization method. +exports.OAuth2.prototype.setAuthMethod = function ( authMethod ) { + this._authMethod = authMethod; +}; + + +// If you use the OAuth2 exposed 'get' method (and don't construct your own _request call ) +// this will specify whether to use an 'Authorize' header instead of passing the access_token as a query parameter +exports.OAuth2.prototype.useAuthorizationHeaderforGET = function(useIt) { + this._useAuthorizationHeaderForGET= useIt; +} + exports.OAuth2.prototype._getAccessTokenUrl= function() { return this._baseSite + this._accessTokenUrl; /* + "?" + querystring.stringify(params); */ } +// Build the authorization header. In particular, build the part after the colon. +// e.g. Authorization: Bearer # Build "Bearer " +exports.OAuth2.prototype.buildAuthHeader= function(token) { + return this._authMethod + ' ' + token; +}; + +exports.OAuth2.prototype._chooseHttpLibrary= function( parsedUrl ) { + var http_library= https; + // As this is OAUth2, we *assume* https unless told explicitly otherwise. + if( parsedUrl.protocol != "https:" ) { + http_library= http; + } + return http_library; +}; + exports.OAuth2.prototype._request= function(method, url, headers, post_body, access_token, callback) { - var creds = crypto.createCredentials({ }); - var parsedUrl= URL.parse( url, true ); - if( parsedUrl.protocol == "https:" && !parsedUrl.port ) parsedUrl.port= 443; - + var creds = crypto.createCredentials({ }); + var parsedUrl= URL.parse( url, true ); + if( parsedUrl.protocol == "https:" && !parsedUrl.port ) { + parsedUrl.port= 443; + } + + var http_library= this._chooseHttpLibrary( parsedUrl ); + + var realHeaders= {}; + for( var key in this._customHeaders ) { + realHeaders[key]= this._customHeaders[key]; + } if( headers ) { for(var key in headers) { realHeaders[key] = headers[key]; @@ -40,13 +80,25 @@ exports.OAuth2.prototype._request= function(method, url, headers, post_body, acc } realHeaders['Host']= parsedUrl.host; - realHeaders['Content-Length']= post_body ? Buffer.byteLength(post_body) : 0; - if( access_token ) { + if (!realHeaders['User-Agent']) { + realHeaders['User-Agent'] = 'Node-oauth'; + } + + if( post_body ) { + if ( Buffer.isBuffer(post_body) ) { + realHeaders["Content-Length"]= post_body.length; + } else { + realHeaders["Content-Length"]= Buffer.byteLength(post_body); + } + } else { + realHeaders["Content-length"]= 0; + } + + if( access_token && !('Authorization' in realHeaders)) { if( ! parsedUrl.query ) parsedUrl.query= {}; parsedUrl.query[this._accessTokenName]= access_token; } - var result= ""; var queryStr= querystring.stringify(parsedUrl.query); if( queryStr ) queryStr= "?" + queryStr; var options = { @@ -57,6 +109,10 @@ exports.OAuth2.prototype._request= function(method, url, headers, post_body, acc headers: realHeaders }; + this._executeRequest( http_library, options, post_body, callback ); +} + +exports.OAuth2.prototype._executeRequest= function( http_library, options, post_body, callback ) { // Some hosts *cough* google appear to close the connection early / send no content-length header // allow this behaviour. var allowEarlyClose= OAuthUtils.isAnEarlyCloseHost(options.host); @@ -64,7 +120,7 @@ exports.OAuth2.prototype._request= function(method, url, headers, post_body, acc function passBackControl( response, result ) { if(!callbackCalled) { callbackCalled=true; - if( response.statusCode != 200 ) { + if( response.statusCode != 200 && (response.statusCode != 301) && (response.statusCode != 302) ) { callback({ statusCode: response.statusCode, data: result }); } else { callback(null, result, response); @@ -72,7 +128,9 @@ exports.OAuth2.prototype._request= function(method, url, headers, post_body, acc } } - request = https.request(options, function (response) { + var result= ""; + + var request = http_library.request(options, function (response) { response.on("data", function (chunk) { result+= chunk }); @@ -90,17 +148,15 @@ exports.OAuth2.prototype._request= function(method, url, headers, post_body, acc callback(e); }); - if( method == 'POST' && post_body ) { + if( (options.method == 'POST' || options.method == 'PUT') && post_body ) { request.write(post_body); } request.end(); -} - +} exports.OAuth2.prototype.getAuthorizeUrl= function( params ) { var params= params || {}; params['client_id'] = this._clientId; - params['type'] = 'web_server'; return this._baseSite + this._authorizeUrl + "?" + querystring.stringify(params); } @@ -108,8 +164,8 @@ exports.OAuth2.prototype.getOAuthAccessToken= function(code, params, callback) { var params= params || {}; params['client_id'] = this._clientId; params['client_secret'] = this._clientSecret; - params['type']= 'web_server'; - params['code']= code; + var codeParam = (params.grant_type === 'refresh_token') ? 'refresh_token' : 'code'; + params[codeParam]= code; var post_data= querystring.stringify( params ); var post_headers= { @@ -136,10 +192,10 @@ exports.OAuth2.prototype.getOAuthAccessToken= function(code, params, callback) { var access_token= results["access_token"]; var refresh_token= results["refresh_token"]; delete results["refresh_token"]; - callback(null, access_token, refresh_token); + callback(null, access_token, refresh_token, results); // callback results =-= } }); -} +} // Deprecated exports.OAuth2.prototype.getProtectedResource= function(url, access_token, callback) { @@ -147,5 +203,12 @@ exports.OAuth2.prototype.getProtectedResource= function(url, access_token, callb } exports.OAuth2.prototype.get= function(url, access_token, callback) { - this._request("GET", url, {}, "", access_token, callback ); + if( this._useAuthorizationHeaderForGET ) { + var headers= {'Authorization': this.buildAuthHeader(access_token) } + access_token= null; + } + else { + headers= {}; + } + this._request("GET", url, headers, "", access_token, callback ); } diff --git a/node_modules/twitter/node_modules/oauth/lib/poo.diff b/node_modules/twitter/node_modules/oauth/lib/poo.diff deleted file mode 100644 index 6c0d0da..0000000 --- a/node_modules/twitter/node_modules/oauth/lib/poo.diff +++ /dev/null @@ -1,136 +0,0 @@ -diff --git a/lib/oauth2.js b/lib/oauth2.js -index 4713192..e1496e7 100644 ---- a/lib/oauth2.js -+++ b/lib/oauth2.js -@@ -21,16 +21,16 @@ exports.OAuth2.prototype.setAccessTokenName= function ( name ) { - this._accessTokenName= name; - } - --exports.OAuth2.prototype._getAccessTokenUrl= function( params ) { -- var params= params || {}; -- params['client_id'] = this._clientId; -- params['client_secret'] = this._clientSecret; -- params['type']= 'web_server'; -- -- return this._baseSite + this._accessTokenUrl + "?" + querystring.stringify(params); -+exports.OAuth2.prototype._getAccessTokenUrl= function() { -+ return this._baseSite + this._accessTokenUrl; /* + "?" + querystring.stringify(params); */ - } - --exports.OAuth2.prototype._request= function(method, url, headers, access_token, callback) { -+// Returns true if this is a host that closes *before* it ends?!?! -+exports.OAuth2.prototype._isAnEarlyCloseHost= function( hostName ) { -+ return hostName.match(".*google.com$") -+} -+ -+exports.OAuth2.prototype._request= function(method, url, headers, post_body, access_token, callback) { - - var creds = crypto.createCredentials({ }); - var parsedUrl= URL.parse( url, true ); -@@ -44,40 +44,63 @@ exports.OAuth2.prototype._request= function(method, url, headers, access_token, - } - realHeaders['Host']= parsedUrl.host; - -+ // I imagine this is an efficient cost, but google API just holds the connection open otherwise :( -+ realHeaders['Connection']='close'; -+ - //TODO: Content length should be dynamic when dealing with POST methods.... -- realHeaders['Content-Length']= 0; -+ realHeaders['Content-Length']= post_body ? Buffer.byteLength(post_body) : 0; - if( access_token ) { - if( ! parsedUrl.query ) parsedUrl.query= {}; - parsedUrl.query[this._accessTokenName]= access_token; - } - - var result= ""; -- -+ var queryStr= querystring.stringify(parsedUrl.query); -+ if( queryStr ) queryStr= "?" + queryStr; - var options = { - host:parsedUrl.hostname, - port: parsedUrl.port, -- path: parsedUrl.pathname + "?" + querystring.stringify(parsedUrl.query), -+ path: parsedUrl.pathname + queryStr, - method: method, - headers: realHeaders - }; -- -- request = https.request(options, function (response) { -- response.addListener("data", function (chunk) { -- result+= chunk -- }); -- response.addListener("end", function () { -+ -+ // Some hosts *cough* google appear to close the connection early / send no content-length header -+ // allow this behaviour. -+ var allowEarlyClose= this._isAnEarlyCloseHost(options.host); -+ var callbackCalled= false; -+ function passBackControl( response, result ) { -+ if(!callbackCalled) { -+ callbackCalled=true; - if( response.statusCode != 200 ) { - callback({ statusCode: response.statusCode, data: result }); - } else { - callback(null, result, response); - } -+ } -+ } -+ -+ request = https.request(options, function (response) { -+ response.on("data", function (chunk) { -+ result+= chunk -+ }); -+ response.on("close", function (err) { -+ if( allowEarlyClose ) { -+ passBackControl( response, result ); -+ } -+ }); -+ response.addListener("end", function () { -+ passBackControl( response, result ); - }); - }); -- - request.on('error', function(e) { -+ callbackCalled= true; - callback(e); - }); - -+ if( method == 'POST' && post_body ) { -+ request.write(post_body); -+ } - request.end(); - } - -@@ -91,9 +114,19 @@ exports.OAuth2.prototype.getAuthorizeUrl= function( params ) { - - exports.OAuth2.prototype.getOAuthAccessToken= function(code, params, callback) { - var params= params || {}; -+ params['client_id'] = this._clientId; -+ params['client_secret'] = this._clientSecret; -+ params['type']= 'web_server'; - params['code']= code; -+ -+ var post_data= querystring.stringify( params ); -+ var post_headers= { -+ 'Content-Type': 'application/x-www-form-urlencoded' -+ }; -+ - -- this._request("POST", this._getAccessTokenUrl(params), {}, null, function(error, data, response) { -+ this._request("POST", this._getAccessTokenUrl(), post_headers, post_data, null, function(error, data, response) { -+ console.log( 'e> ' + error) - if( error ) callback(error); - else { - var results; -@@ -119,9 +152,9 @@ exports.OAuth2.prototype.getOAuthAccessToken= function(code, params, callback) { - - // Deprecated - exports.OAuth2.prototype.getProtectedResource= function(url, access_token, callback) { -- this._request("GET", url, {}, access_token, callback ); -+ this._request("GET", url, {}, "", access_token, callback ); - } - - exports.OAuth2.prototype.get= function(url, access_token, callback) { -- this._request("GET", url, {}, access_token, callback ); -+ this._request("GET", url, {}, "", access_token, callback ); - } diff --git a/node_modules/twitter/node_modules/oauth/merge_coopernurse b/node_modules/twitter/node_modules/oauth/merge_coopernurse deleted file mode 100644 index e69de29..0000000 diff --git a/node_modules/twitter/node_modules/oauth/numero-test.js b/node_modules/twitter/node_modules/oauth/numero-test.js deleted file mode 100644 index 036b732..0000000 --- a/node_modules/twitter/node_modules/oauth/numero-test.js +++ /dev/null @@ -1,29 +0,0 @@ -//var OAuth= require('./lib/oauth').OAuth; -var sys= require('sys'); -var OAuth= require('oauth').OAuth; - -oa= new OAuth("https://tes-ws.numerosoftware.co.uk/websuite/oauth/accesstokens", - "https://test-ws.numerosoftware.co.uk/websuite/oauth/access_token", - "tesco-websuite", "dc935a53-4e1d-4120-a4e4-cd8e2d1ab481", - "1.0A", "ootb", "HMAC-SHA1"); - -oa.getOAuthRequestToken(function(error, oauth_token, oauth_token_secret, results){ - if(error) sys.puts('error :' + JSON.stringify(error)) - else { - sys.puts('oauth_token: ' + oauth_token) - sys.puts('oauth_token_secret: ' + oauth_token_secret) - sys.puts('requestoken results: ' + sys.inspect(results)) - sys.puts("Requesting access token") - oa.getOAuthAccessToken(oauth_token, oauth_token_secret, 'verifier', function(error, oauth_access_token, oauth_access_token_secret, results2) { - sys.puts('oauth_access_token: ' + oauth_access_token) - sys.puts('oauth_token_secret: ' + oauth_access_token_secret) - sys.puts('accesstoken results: ' + sys.inspect(results2)) - sys.puts("Requesting secure schznit") - var data= ""; - oa.getProtectedResource("http://localhost:3000/fetch/unicorns?foo=bar&too=roo", "GET", oauth_access_token, oauth_access_token_secret, function (error, data, response) { - sys.puts(sys.inspect(error)); - sys.puts(data); - }); - }); - } -}) \ No newline at end of file diff --git a/node_modules/twitter/node_modules/oauth/package.json b/node_modules/twitter/node_modules/oauth/package.json index 64db509..564a652 100644 --- a/node_modules/twitter/node_modules/oauth/package.json +++ b/node_modules/twitter/node_modules/oauth/package.json @@ -1,11 +1,39 @@ -{ "name" : "oauth" -, "description" : "Library for interacting with OAuth 1.0, 1.0A, 2 and Echo. Provides simplified client access and allows for construction of more complex apis and OAuth providers." -, "version" : "0.9.5" -, "directories" : { "lib" : "./lib" } -, "main" : "index.js" -, "author" : "Ciaran Jessup " -, "repository" : { "type":"git", "url":"http://github.com/ciaranj/node-oauth.git" } -, "devDependencies": { +{ + "name": "oauth", + "description": "Library for interacting with OAuth 1.0, 1.0A, 2 and Echo. Provides simplified client access and allows for construction of more complex apis and OAuth providers.", + "version": "0.9.12", + "directories": { + "lib": "./lib" + }, + "main": "index.js", + "author": { + "name": "Ciaran Jessup", + "email": "ciaranj@gmail.com" + }, + "repository": { + "type": "git", + "url": "http://github.com/ciaranj/node-oauth.git" + }, + "devDependencies": { "vows": "0.5.x" - } + }, + "scripts": { + "test": "make test" + }, + "licenses": [ + { + "type": "MIT", + "url": "http://github.com/ciaranj/node-oauth/raw/master/LICENSE" + } + ], + "readme": "node-oauth\n===========\nA simple oauth API for node.js . This API allows users to authenticate against OAUTH providers, and thus act as OAuth consumers. It also has support for OAuth Echo, which is used for communicating with 3rd party media providers such as TwitPic and yFrog.\n\nTested against Twitter (http://twitter.com), term.ie (http://term.ie/oauth/example/), TwitPic, and Yahoo!\n\nAlso provides rudimentary OAuth2 support, tested against facebook, github, foursquare, google and Janrain. For more complete usage examples please take a look at connect-auth (http://github.com/ciaranj/connect-auth)\n\n[![Clone in Koding](http://learn.koding.com/btn/clone_d.png)][koding]\n[koding]: https://koding.com/Teamwork?import=https://github.com/ciaranj/node-oauth/archive/master.zip&c=git1\n\nInstallation\n============== \n\n $ npm install oauth\n\n\nExamples\n==========\n\nTo run examples/tests install Mocha `$ npm install -g mocha` and run `$ mocha you-file-name.js`:\n\n## OAuth1.0\n\n```javascript\ndescribe('OAuth1.0',function(){\n var OAuth = require('oauth');\n\n it('tests trends Twitter API v1.1',function(done){\n var oauth = new OAuth.OAuth(\n 'https://api.twitter.com/oauth/request_token',\n 'https://api.twitter.com/oauth/access_token',\n 'your application consumer key',\n 'your application secret',\n '1.0A',\n null,\n 'HMAC-SHA1'\n );\n oauth.get(\n 'https://api.twitter.com/1.1/trends/place.json?id=23424977',\n 'your user token for this app', //test user token\n 'your user secret for this app', //test user secret \n function (e, data, res){\n if (e) console.error(e); \n console.log(require('util').inspect(data));\n done(); \n }); \n });\n});\n```\n\n## OAuth2.0 \n```javascript\ndescribe('OAuth2',function(){\n var OAuth = require('oauth');\n\n it('gets bearer token', function(done){\n var OAuth2 = OAuth.OAuth2; \n var twitterConsumerKey = 'your key';\n var twitterConsumerSecret = 'your secret';\n var oauth2 = new OAuth2(server.config.keys.twitter.consumerKey,\n twitterConsumerSecret, \n 'https://api.twitter.com/', \n null,\n 'oauth2/token', \n null);\n oauth2.getOAuthAccessToken(\n '',\n {'grant_type':'client_credentials'},\n function (e, access_token, refresh_token, results){\n console.log('bearer: ',access_token);\n done();\n });\n });\n```\n\nChange History\n============== \n\n* 0.9.12\n - OAuth1/2: Can now pass Buffer instance directly for PUTs+POSTs (thank you Evan Prodromou)\n - OAuth1: Improve interoperability with libraries that mess with the prototype. (thank you Jose Ignacio Andres)\n - OAuth2: Adds PUT support for OAuth2 (thank you Derek Brooks)\n - OAuth1: Improves use_strict compatibility (thank you Ted Goddard)\n* 0.9.11\n - OAuth2: No longer sends the type=webserver argument with the OAuth2 requests (thank you bendiy)\n - OAuth2: Provides a default (and overrideable) User-Agent header (thanks to Andrew Martens & Daniel Mahlow)\n - OAuth1: New followRedirects client option (true by default) (thanks to Pieter Joost van de Sande)\n - OAuth1: Adds RSA-SHA1 support (thanks to Jeffrey D. Van Alstine & Michael Garvin & Andreas Knecht)\n* 0.9.10\n - OAuth2: Addresses 2 issues that came in with 0.9.9, #129 & #125 (thank you José F. Romaniello)\n* 0.9.9\n - OAuth1: Fix the mismatch between the output of querystring.stringify() and this._encodeData(). (thank you rolandboon)\n - OAuth2: Adds Authorization Header and supports extra headers by default ( thanks to Brian Park)\n* 0.9.8\n - OAuth1: Support overly-strict OAuth server's that require whitespace separating the Authorization Header parameters (e.g. 500px.com) (Thanks to Christian Schwarz)\n - OAuth1: Fix incorrect double-encoding of PLAINTEXT OAuth connections (Thanks to Joe Rozner)\n - OAuth1: Minor safety check added when checking hostnames. (Thanks to Garrick Cheung)\n* 0.9.7\n - OAuth2: Pass back any extra response data for calls to getOAuthAccessToken (Thanks to Tang Bo Hao)\n - OAuth2: Don't force a https request if given a http url (Thanks to Damien Mathieu)\n - OAuth2: Supports specifying a grant-type of 'refresh-token' (Thanks to Luke Baker)\n* 0.9.6\n - OAuth2: Support for 302 redirects (Thanks Patrick Negri). \n - OAuth1/2: Some code tidying. ( Thanks to Raoul Millais ) \n* 0.9.5\n - OAuth1: Allow usage of HTTP verbs other than GET for retrieving the access and request tokens (Thanks to Raoul Millais) \n* 0.9.4\n - OAuth1/2: Support for OAuth providers that drop connections (don't send response lengths? [Google]) \n - OAuth2: Change getOAuthAccessToken to POST rather than GET ( Possible Breaking change!!! ... re-tested against Google, Github, Facebook, FourSquare and Janrain and seems ok .. is closer to the spec (v20) ) \n* 0.9.3\n - OAuth1: Adds support for following 301 redirects (Thanks bdickason) \n* 0.9.2 \n - OAuth1: Correct content length calculated for non-ascii post bodies (Thanks selead) \n - OAuth1: Allowed for configuration of the 'access token' name used when requesting protected resources (OAuth2) \n* 0.9.1\n - OAuth1: Added support for automatically following 302 redirects (Thanks neyric) \n - OAuth1: Added support for OAuth Echo (Thanks Ryan LeFevre). \n - OAuth1: Improved handling of 2xx responses (Thanks Neil Mansilla). \n* 0.9.0\n - OAuth1/2: Compatibility fixes to bring node-oauth up to speed with node.js 0.4x [thanks to Rasmus Andersson for starting the work ] \n* 0.8.4\n - OAuth1: Fixed issue #14 (Parameter ordering ignored encodings).\n - OAuth1: Added support for repeated parameter names.\n - OAuth1/2: Implements issue #15 (Use native SHA1 if available, 10x speed improvement!).\n - OAuth2: Fixed issue #16 (Should use POST when requesting access tokens.).\n - OAuth2: Fixed Issue #17 (OAuth2 spec compliance). \n - OAuth1: Implemented enhancement #13 (Adds support for PUT & DELETE http verbs). \n - OAuth1: Fixes issue #18 (Complex/Composite url arguments [thanks novemberborn]) \n* 0.8.3\n - OAuth1: Fixed an issue where the auth header code depended on the Array's toString method (Yohei Sasaki) Updated the getOAuthRequestToken method so we can access google's OAuth secured methods. Also re-implemented and fleshed out the test suite. \n* 0.8.2\n - OAuth1: The request returning methods will now write the POST body if provided (Chris Anderson), the code responsible for manipulating the headers is a bit safe now when working with other code (Paul McKellar)\n - Package: Tweaked the package.json to use index.js instead of main.js \n* 0.8.1\n - OAuth1: Added mechanism to get hold of a signed Node Request object, ready for attaching response listeners etc. (Perfect for streaming APIs) \n* 0.8.0\n - OAuth1: Standardised method capitalisation, the old getOauthAccessToken is now getOAuthAccessToken (Breaking change to existing code) \n* 0.7.7\n - OAuth1: Looks like non oauth_ parameters where appearing within the Authorization headers, which I believe to be incorrect. \n* 0.7.6\n - OAuth1: Added in oauth_verifier property to getAccessToken required for 1.0A \n* 0.7.5\n - Package: Added in a main.js to simplify the require'ing of OAuth \n* 0.7.4\n - OAuth1: Minor change to add an error listener to the OAuth client (thanks troyk) \n* 0.7.3\n - OAuth2: Now sends a Content-Length Http header to keep nginx happy :) \n* 0.7.2\n - OAuth1: Fixes some broken unit tests! \n* 0.7.0\n - OAuth1/2: Introduces support for HTTPS end points and callback URLS for OAuth 1.0A and Oauth 2 (Please be aware that this was a breaking change to the constructor arguments order) \n\nContributors (In no particular order)\n=====================================\n\n* Evan Prodromou\n* Jose Ignacio Andres\n* Ted Goddard\n* Derek Brooks\n* Ciaran Jessup - ciaranj@gmail.com\n* Mark Wubben - http://equalmedia.com/\n* Ryan LeFevre - http://meltingice.net\n* Raoul Millais\n* Patrick Negri - http://github.com/pnegri\n* Tang Bo Hao - http://github.com/btspoony\n* Damien Mathieu - http://42.dmathieu.com\n* Luke Baker - http://github.com/lukebaker\n* Christian Schwarz - http://github.com/chrischw/\n* Joe Rozer - http://www.deadbytes.net\n* Garrick Cheung - http://www.garrickcheung.com/\n* rolandboon - http://rolandboon.com\n* Brian Park - http://github.com/yaru22\n* José F. Romaniello - http://github.com/jfromaniello\n* bendiy - https://github.com/bendiy\n* Andrew Martins - http://www.andrewmartens.com\n* Daniel Mahlow - https://github.com/dmahlow\n* Pieter Joost van de Sande - https://github.com/pjvds\n* Jeffrey D. Van Alstine\n* Michael Garvin\n* Andreas Knecht\n", + "readmeFilename": "Readme.md", + "bugs": { + "url": "https://github.com/ciaranj/node-oauth/issues" + }, + "homepage": "https://github.com/ciaranj/node-oauth", + "_id": "oauth@0.9.12", + "_shasum": "77bbb77cc5d638fe9b1d111b33c0b2f90030e89c", + "_from": "oauth@>=0.8.4", + "_resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.12.tgz" } diff --git a/node_modules/twitter/node_modules/oauth/test.js b/node_modules/twitter/node_modules/oauth/test.js deleted file mode 100644 index 1c026d3..0000000 --- a/node_modules/twitter/node_modules/oauth/test.js +++ /dev/null @@ -1,29 +0,0 @@ -//var OAuth= require('./lib/oauth').OAuth; -var sys= require('sys'); -var OAuth= require('oauth').OAuth; - -oa= new OAuth("http://localhost:3000/oauth/request_token", - "http://localhost:3000/oauth/access_token", - "JiYmll7CX3AXDgasnnIDeg", "mWPBRK5kG2Tkthuf5zRV1jYWOEwnjI6xs3QVRqOOg", - "1.0A", "http://localhost:3000/oauth/callback", "HMAC-SHA1"); - -oa.getOAuthRequestToken(function(error, oauth_token, oauth_token_secret, results){ - if(error) sys.puts('error :' + error) - else { - sys.puts('oauth_token: ' + oauth_token) - sys.puts('oauth_token_secret: ' + oauth_token_secret) - sys.puts('requestoken results: ' + sys.inspect(results)) - sys.puts("Requesting access token") - oa.getOAuthAccessToken(oauth_token, oauth_token_secret, 'verifier', function(error, oauth_access_token, oauth_access_token_secret, results2) { - sys.puts('oauth_access_token: ' + oauth_access_token) - sys.puts('oauth_token_secret: ' + oauth_access_token_secret) - sys.puts('accesstoken results: ' + sys.inspect(results2)) - sys.puts("Requesting secure schznit") - var data= ""; - oa.getProtectedResource("http://localhost:3000/fetch/unicorns?foo=bar&too=roo", "GET", oauth_access_token, oauth_access_token_secret, function (error, data, response) { - sys.puts(sys.inspect(error)); - sys.puts(data); - }); - }); - } -}) \ No newline at end of file diff --git a/node_modules/twitter/node_modules/oauth/testb.js b/node_modules/twitter/node_modules/oauth/testb.js deleted file mode 100644 index 47fa0e0..0000000 --- a/node_modules/twitter/node_modules/oauth/testb.js +++ /dev/null @@ -1,35 +0,0 @@ -//var OAuth= require('./lib/oauth').OAuth; -var sys= require('sys'); -var OAuth= require('./lib/oauth').OAuth; - -oa= new OAuth("https://twitter.com/oauth/request_token", - "https://twitter.com/oauth/access_token", - "RuN9ovM7vvXyOO1N6DmhsA", "qpUPDJJasO5G2jZenK3m7t7pAcA9ZuyUv8WsGnonJo", - "1.0A", "http://localhost:3000/oauth/callback", "HMAC-SHA1"); - -var access_token= '23186482-CpF7lxJx1T2GhJ8fQT3ewvuIpbMtskHcN6craOzly'; -var access_token_secret= '8SqTfcI7uW7lwcBQnnpEsvY59u788s8TS2OmX1AGpKU'; - -/*var request= oa.get("http://stream.twitter.com/1/statuses/filter.json?follow=11528912,9512582", access_token, access_token_secret ); -request.addListener('response', function (response) { - response.setEncoding('utf8'); - response.addListener('data', function (chunk) { - console.log(chunk); - }); - response.addListener('end', function () { - console.log('--- END ---') - }); -}); - -request.end(); -*/ -/* -oa.get("http://api.twitter.com/1/statuses/retweeted_by_me.json", access_token, access_token_secret, function(error, data) { - console.log(sys.inspect(data)); -});*/ - -oa.post("http://api.twitter.com/1/statuses/update.json", access_token, access_token_secret, - {"status":"Just testing one of my OAuth libs for compatability issues, sorry!"}, function(e,d){ - console.log(sys.inspect(e)); - console.log(sys.inspect(d)); -}); \ No newline at end of file diff --git a/node_modules/twitter/node_modules/oauth/tests/oauth.js b/node_modules/twitter/node_modules/oauth/tests/oauth.js index b52f1e5..e88b754 100644 --- a/node_modules/twitter/node_modules/oauth/tests/oauth.js +++ b/node_modules/twitter/node_modules/oauth/tests/oauth.js @@ -2,7 +2,8 @@ var vows = require('vows'), assert = require('assert'), events = require('events'), OAuth= require('../lib/oauth').OAuth, - OAuthEcho= require('../lib/oauth').OAuthEcho; + OAuthEcho= require('../lib/oauth').OAuthEcho, + crypto = require('crypto'); var DummyResponse =function( statusCode ) { this.statusCode= statusCode; @@ -21,17 +22,70 @@ DummyRequest.prototype.write= function(post_body){ } DummyRequest.prototype.end= function(){ this.response.emit('end'); -} +} + +//Valid RSA keypair used to test RSA-SHA1 signature method +var RsaPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\n" + +"MIICXQIBAAKBgQDizE4gQP5nPQhzof/Vp2U2DDY3UY/Gxha2CwKW0URe7McxtnmE\n" + +"CrZnT1n/YtfrrCNxY5KMP4o8hMrxsYEe05+1ZGFT68ztms3puUxilU5E3BQMhz1t\n" + +"JMJEGcTt8nZUlM4utli7fHgDtWbhvqvYjRMGn3AjyLOfY8XZvnFkGjipvQIDAQAB\n" + +"AoGAKgk6FcpWHOZ4EY6eL4iGPt1Gkzw/zNTcUsN5qGCDLqDuTq2Gmk2t/zn68VXt\n" + +"tVXDf/m3qN0CDzOBtghzaTZKLGhnSewQ98obMWgPcvAsb4adEEeW1/xigbMiaW2X\n" + +"cu6GhZxY16edbuQ40LRrPoVK94nXQpj8p7w4IQ301Sm8PSECQQD1ZlOj4ugvfhEt\n" + +"exi4WyAaM45fylmN290UXYqZ8SYPI/VliDytIlMfyq5Rv+l+dud1XDPrWOQ0ImgV\n" + +"HJn7uvoZAkEA7JhHNmHF9dbdF9Koj86K2Cl6c8KUu7U7d2BAuB6pPkt8+D8+y4St\n" + +"PaCmN4oP4X+sf5rqBYoXywHlqEei2BdpRQJBAMYgR4cZu7wcXGIL8HlnmROObHSK\n" + +"OqN9z5CRtUV0nPW8YnQG+nYOMG6KhRMbjri750OpnYF100kEPmRNI0VKQIECQE8R\n" + +"fQsRleTYz768ahTVQ9WF1ySErMwmfx8gDcD6jjkBZVxZVpURXAwyehopi7Eix/VF\n" + +"QlxjkBwKIEQi3Ks297kCQQCL9by1bueKDMJO2YX1Brm767pkDKkWtGfPS+d3xMtC\n" + +"KJHHCqrS1V+D5Q89x5wIRHKxE5UMTc0JNa554OxwFORX\n" + +"-----END RSA PRIVATE KEY-----"; + +var RsaPublicKey = "-----BEGIN PUBLIC KEY-----\n" + +"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDizE4gQP5nPQhzof/Vp2U2DDY3\n" + +"UY/Gxha2CwKW0URe7McxtnmECrZnT1n/YtfrrCNxY5KMP4o8hMrxsYEe05+1ZGFT\n" + +"68ztms3puUxilU5E3BQMhz1tJMJEGcTt8nZUlM4utli7fHgDtWbhvqvYjRMGn3Aj\n" + +"yLOfY8XZvnFkGjipvQIDAQAB\n" + +"-----END PUBLIC KEY-----"; vows.describe('OAuth').addBatch({ + 'When newing OAuth': { + topic: new OAuth(null, null, null, null, null, null, "PLAINTEXT"), + 'followRedirects is enabled by default': function (oa) { + assert.equal(oa._clientOptions.followRedirects, true) + } + }, 'When generating the signature base string described in http://oauth.net/core/1.0/#sig_base_example': { topic: new OAuth(null, null, null, null, null, null, "HMAC-SHA1"), 'we get the expected result string': function (oa) { - var result= oa._createSignatureBase("GET", "http://photos.example.net/photos", + var result= oa._createSignatureBase("GET", "http://photos.example.net/photos", "file=vacation.jpg&oauth_consumer_key=dpf43f3p2l4k3l03&oauth_nonce=kllo9940pd9333jh&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1191242096&oauth_token=nnch734d00sl2jdk&oauth_version=1.0&size=original") assert.equal( result, "GET&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacation.jpg%26oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%3Dkllo9940pd9333jh%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1191242096%26oauth_token%3Dnnch734d00sl2jdk%26oauth_version%3D1.0%26size%3Doriginal"); } }, + 'When generating the signature with RSA-SHA1': { + topic: new OAuth(null, null, null, RsaPrivateKey, null, null, "RSA-SHA1"), + 'we get a valid oauth signature': function (oa) { + var signatureBase = "GET&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacation.jpg%26oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%3Dkllo9940pd9333jh%26oauth_signature_method%3DRSA-SHA1%26oauth_timestamp%3D1191242096%26oauth_token%3Dnnch734d00sl2jdk%26oauth_version%3D1.0%26size%3Doriginal"; + var oauthSignature = oa._createSignature(signatureBase, "xyz4992k83j47x0b"); + + assert.equal( oauthSignature, "qS4rhWog7GPgo4ZCJvUdC/1ZAax/Q4Ab9yOBvgxSopvmKUKp5rso+Zda46GbyN2hnYDTiA/g3P/d/YiPWa454BEBb/KWFV83HpLDIoqUUhJnlXX9MqRQQac0oeope4fWbGlfTdL2PXjSFJmvfrzybERD/ZufsFtVrQKS3QBpYiw="); + + //now check that given the public key we can verify this signature + var verifier = crypto.createVerify("RSA-SHA1").update(signatureBase); + var valid = verifier.verify(RsaPublicKey, oauthSignature, 'base64'); + assert.ok( valid, "Signature could not be verified with RSA public key"); + } + }, + 'When generating the signature base string with PLAINTEXT': { + topic: new OAuth(null, null, null, null, null, null, "PLAINTEXT"), + 'we get the expected result string': function (oa) { + var result= oa._getSignature("GET", "http://photos.example.net/photos", + "file=vacation.jpg&oauth_consumer_key=dpf43f3p2l4k3l03&oauth_nonce=kllo9940pd9333jh&oauth_signature_method=PLAINTEXT&oauth_timestamp=1191242096&oauth_token=nnch734d00sl2jdk&oauth_version=1.0&size=original", + "test"); + assert.equal( result, "&test"); + } + }, 'When normalising a url': { topic: new OAuth(null, null, null, null, null, null, "HMAC-SHA1"), 'default ports should be stripped': function(oa) { @@ -49,7 +103,7 @@ vows.describe('OAuth').addBatch({ topic: new OAuth(null, null, null, null, null, null, "HMAC-SHA1"), 'flatten out arguments that are arrays' : function(oa) { var parameters= {"z": "a", - "a": ["1", "2"], + "a": ["1", "2"], "1": "c" }; var parameterResults= oa._makeArrayOfArgumentsHash(parameters); assert.equal(parameterResults.length, 4); @@ -63,30 +117,30 @@ vows.describe('OAuth').addBatch({ topic: new OAuth(null, null, null, null, null, null, "HMAC-SHA1"), 'Order them by name' : function(oa) { var parameters= {"z": "a", - "a": "b", + "a": "b", "1": "c" }; var parameterResults= oa._sortRequestParams(oa._makeArrayOfArgumentsHash(parameters)) assert.equal(parameterResults[0][0], "1"); - assert.equal(parameterResults[1][0], "a"); - assert.equal(parameterResults[2][0], "z"); + assert.equal(parameterResults[1][0], "a"); + assert.equal(parameterResults[2][0], "z"); }, 'If two parameter names are the same then order by the value': function(oa) { var parameters= {"z": "a", - "a": ["z", "b", "b", "a", "y"], + "a": ["z", "b", "b", "a", "y"], "1": "c" }; var parameterResults= oa._sortRequestParams(oa._makeArrayOfArgumentsHash(parameters)) assert.equal(parameterResults[0][0], "1"); - assert.equal(parameterResults[1][0], "a"); - assert.equal(parameterResults[1][1], "a"); - assert.equal(parameterResults[2][0], "a"); - assert.equal(parameterResults[2][1], "b"); - assert.equal(parameterResults[3][0], "a"); - assert.equal(parameterResults[3][1], "b"); - assert.equal(parameterResults[4][0], "a"); - assert.equal(parameterResults[4][1], "y"); - assert.equal(parameterResults[5][0], "a"); - assert.equal(parameterResults[5][1], "z"); - assert.equal(parameterResults[6][0], "z"); + assert.equal(parameterResults[1][0], "a"); + assert.equal(parameterResults[1][1], "a"); + assert.equal(parameterResults[2][0], "a"); + assert.equal(parameterResults[2][1], "b"); + assert.equal(parameterResults[3][0], "a"); + assert.equal(parameterResults[3][1], "b"); + assert.equal(parameterResults[4][0], "a"); + assert.equal(parameterResults[4][1], "y"); + assert.equal(parameterResults[5][0], "a"); + assert.equal(parameterResults[5][1], "z"); + assert.equal(parameterResults[6][0], "z"); } }, 'When normalising the request parameters': { @@ -180,7 +234,11 @@ vows.describe('OAuth').addBatch({ }, 'Provide a valid signature when a token and a token secret is present': function(oa) { assert.equal( oa.authHeader("http://somehost.com:3323/foo/poop?bar=foo", "token", "tokensecret"), 'OAuth oauth_consumer_key="consumerkey",oauth_nonce="ybHPeOEkAUJ3k2wJT9Xb43MjtSgTvKqp",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1272399856",oauth_token="token",oauth_version="1.0",oauth_signature="zeOR0Wsm6EG6XSg0Vw%2FsbpoSib8%3D"'); - } + }, + 'Support variable whitespace separating the arguments': function(oa) { + oa._oauthParameterSeperator= ", "; + assert.equal( oa.authHeader("http://somehost.com:3323/foo/poop?bar=foo", "token", "tokensecret"), 'OAuth oauth_consumer_key="consumerkey", oauth_nonce="ybHPeOEkAUJ3k2wJT9Xb43MjtSgTvKqp", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1272399856", oauth_token="token", oauth_version="1.0", oauth_signature="zeOR0Wsm6EG6XSg0Vw%2FsbpoSib8%3D"'); + } }, 'When get the OAuth Echo authorization header': { topic: function () { @@ -216,7 +274,7 @@ vows.describe('OAuth').addBatch({ } }, 'When building the OAuth Authorization header': { - topic: new OAuth(null, null, null, null, null, null, "HMAC-SHA1"), + topic: new OAuth(null, null, null, null, null, null, "HMAC-SHA1"), 'All provided oauth arguments should be concatentated correctly' : function(oa) { var parameters= [ ["oauth_timestamp", "1234567"], @@ -224,7 +282,7 @@ vows.describe('OAuth').addBatch({ ["oauth_version", "1.0"], ["oauth_signature_method", "HMAC-SHA1"], ["oauth_consumer_key", "asdasdnm2321b3"]]; - assert.equal(oa._buildAuthorizationHeaders(parameters), 'OAuth oauth_timestamp="1234567",oauth_nonce="ABCDEF",oauth_version="1.0",oauth_signature_method="HMAC-SHA1",oauth_consumer_key="asdasdnm2321b3"'); + assert.equal(oa._buildAuthorizationHeaders(parameters), 'OAuth oauth_timestamp="1234567",oauth_nonce="ABCDEF",oauth_version="1.0",oauth_signature_method="HMAC-SHA1",oauth_consumer_key="asdasdnm2321b3"'); }, '*Only* Oauth arguments should be concatentated, others should be disregarded' : function(oa) { var parameters= [ @@ -236,7 +294,7 @@ vows.describe('OAuth').addBatch({ ["oauth_signature_method", "HMAC-SHA1"], ["oauth_consumer_key", "asdasdnm2321b3"], ["foobar", "asdasdnm2321b3"]]; - assert.equal(oa._buildAuthorizationHeaders(parameters), 'OAuth oauth_timestamp="1234567",oauth_nonce="ABCDEF",oauth_version="1.0",oauth_signature_method="HMAC-SHA1",oauth_consumer_key="asdasdnm2321b3"'); + assert.equal(oa._buildAuthorizationHeaders(parameters), 'OAuth oauth_timestamp="1234567",oauth_nonce="ABCDEF",oauth_version="1.0",oauth_signature_method="HMAC-SHA1",oauth_consumer_key="asdasdnm2321b3"'); }, '_buildAuthorizationHeaders should not depends on Array.prototype.toString' : function(oa) { var _toString = Array.prototype.toString; @@ -318,7 +376,57 @@ vows.describe('OAuth').addBatch({ } } }, - 'if the post_body is not a string' : { + 'if the post_body is a buffer' : { + "It should be passed through as is, and the original content-type (if specified) should be passed through": function(oa) { + var op= oa._createClient; + try { + var callbackCalled= false; + oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) { + assert.equal(headers["Content-Type"], "image/jpeg") + return { + write: function(data){ + callbackCalled= true; + assert.equal(data.length, 4); + }, + on: function() {}, + end: function() { + } + }; + } + var request= oa.post("http://foo.com/blah", "token", "token_secret", new Buffer([10,20,30,40]), "image/jpeg") + assert.equal(callbackCalled, true); + } + finally { + oa._createClient= op; + } + }, + "It should be passed through as is, and no content-type is specified.": function(oa) { + //Should probably actually set application/octet-stream, but to avoid a change in behaviour + // will just document (here) that the library will set it to application/x-www-form-urlencoded + var op= oa._createClient; + try { + var callbackCalled= false; + oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) { + assert.equal(headers["Content-Type"], "application/x-www-form-urlencoded") + return { + write: function(data){ + callbackCalled= true; + assert.equal(data.length, 4); + }, + on: function() {}, + end: function() { + } + }; + } + var request= oa.post("http://foo.com/blah", "token", "token_secret", new Buffer([10,20,30,40])) + assert.equal(callbackCalled, true); + } + finally { + oa._createClient= op; + } + } + }, + 'if the post_body is not a string or a buffer' : { "It should be url encoded and the content type set to be x-www-form-urlencoded" : function(oa) { var op= oa._createClient; try { @@ -350,7 +458,7 @@ vows.describe('OAuth').addBatch({ var testStringLength= testString.length; var testStringBytesLength= Buffer.byteLength(testString); assert.notEqual(testStringLength, testStringBytesLength); // Make sure we're testing a string that differs between byte-length and char-length! - + var op= oa._createClient; try { var callbackCalled= false; @@ -403,7 +511,7 @@ vows.describe('OAuth').addBatch({ "and a post_content_type is specified" : { "It should be written as is, with a content length specified, and the encoding should be set to be as specified" : function(oa) { var op= oa._createClient; - try { + try { var callbackCalled= false; oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) { assert.equal(headers["Content-Type"], "unicorn/encoded"); @@ -432,7 +540,7 @@ vows.describe('OAuth').addBatch({ 'if no callback is passed' : { 'it should return a request object': function(oa) { var request= oa.get("http://foo.com/blah", "token", "token_secret") - assert.isObject(request); + assert.isObject(request); assert.equal(request.method, "GET"); request.end(); } @@ -458,7 +566,7 @@ vows.describe('OAuth').addBatch({ oa._createClient= op; } } - } + }, }, 'PUT' : { 'if no callback is passed' : { @@ -494,6 +602,56 @@ vows.describe('OAuth').addBatch({ } } }, + 'if the post_body is a buffer' : { + "It should be passed through as is, and the original content-type (if specified) should be passed through": function(oa) { + var op= oa._createClient; + try { + var callbackCalled= false; + oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) { + assert.equal(headers["Content-Type"], "image/jpeg") + return { + write: function(data){ + callbackCalled= true; + assert.equal(data.length, 4); + }, + on: function() {}, + end: function() { + } + }; + } + var request= oa.put("http://foo.com/blah", "token", "token_secret", new Buffer([10,20,30,40]), "image/jpeg") + assert.equal(callbackCalled, true); + } + finally { + oa._createClient= op; + } + }, + "It should be passed through as is, and no content-type is specified.": function(oa) { + //Should probably actually set application/octet-stream, but to avoid a change in behaviour + // will just document (here) that the library will set it to application/x-www-form-urlencoded + var op= oa._createClient; + try { + var callbackCalled= false; + oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) { + assert.equal(headers["Content-Type"], "application/x-www-form-urlencoded") + return { + write: function(data){ + callbackCalled= true; + assert.equal(data.length, 4); + }, + on: function() {}, + end: function() { + } + }; + } + var request= oa.put("http://foo.com/blah", "token", "token_secret", new Buffer([10,20,30,40])) + assert.equal(callbackCalled, true); + } + finally { + oa._createClient= op; + } + } + }, 'if the post_body is not a string' : { "It should be url encoded and the content type set to be x-www-form-urlencoded" : function(oa) { var op= oa._createClient; @@ -543,11 +701,11 @@ vows.describe('OAuth').addBatch({ "and a post_content_type is specified" : { "It should be written as is, with a content length specified, and the encoding should be set to be as specified" : function(oa) { var op= oa._createClient; - try { + try { var callbackCalled= false; oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) { assert.equal(headers["Content-Type"], "unicorn/encoded"); - assert.equal(headers["Content-length"], 23); + assert.equal(headers["Content-length"], 23); return { write: function(data) { callbackCalled= true; @@ -569,7 +727,7 @@ vows.describe('OAuth').addBatch({ 'if no callback is passed' : { 'it should return a request object': function(oa) { var request= oa.delete("http://foo.com/blah", "token", "token_secret") - assert.isObject(request); + assert.isObject(request); assert.equal(request.method, "DELETE"); request.end(); } @@ -615,7 +773,7 @@ vows.describe('OAuth').addBatch({ } finally { oa._createClient= op; - } + } } }, 'and a 210 response code is received' : { @@ -635,7 +793,7 @@ vows.describe('OAuth').addBatch({ } finally { oa._createClient= op; - } + } } }, 'And A 301 redirect is received' : { @@ -704,6 +862,78 @@ vows.describe('OAuth').addBatch({ oa._createClient= op; } } + }, + 'and followRedirect is true' : { + 'it should (re)perform the secure request but with the new location' : function(oa) { + var op= oa._createClient; + var psr= oa._performSecureRequest; + var responseCounter = 1; + var callbackCalled = false; + var DummyResponse =function() { + if( responseCounter == 1 ){ + this.statusCode= 301; + this.headers= {location:"http://redirectto.com"}; + responseCounter++; + } + else { + this.statusCode= 200; + } + } + DummyResponse.prototype= events.EventEmitter.prototype; + DummyResponse.prototype.setEncoding= function() {} + + try { + oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) { + return new DummyRequest( new DummyResponse() ); + } + oa._performSecureRequest= function( oauth_token, oauth_token_secret, method, url, extra_params, post_body, post_content_type, callback ) { + if( responseCounter == 1 ) { + assert.equal(url, "http://originalurl.com"); + } + else { + assert.equal(url, "http://redirectto.com"); + } + return psr.call(oa, oauth_token, oauth_token_secret, method, url, extra_params, post_body, post_content_type, callback ) + } + + oa._performSecureRequest("token", "token_secret", 'POST', 'http://originalurl.com', {"scope": "foobar,1,2"}, null, null, function() { + // callback + assert.equal(responseCounter, 2); + callbackCalled= true; + }); + assert.equal(callbackCalled, true) + } + finally { + oa._createClient= op; + oa._performSecureRequest= psr; + } + } + }, + 'and followRedirect is false' : { + 'it should not perform the secure request with the new location' : function(oa) { + var op= oa._createClient; + oa.setClientOptions({ followRedirects: false }); + var DummyResponse =function() { + this.statusCode= 301; + this.headers= {location:"http://redirectto.com"}; + } + DummyResponse.prototype= events.EventEmitter.prototype; + DummyResponse.prototype.setEncoding= function() {} + + try { + oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) { + return new DummyRequest( new DummyResponse() ); + } + oa._performSecureRequest("token", "token_secret", 'POST', 'http://originalurl.com', {"scope": "foobar,1,2"}, null, null, function(res, data, response) { + // callback + assert.equal(res.statusCode, 301); + }); + } + finally { + oa._createClient= op; + oa.setClientOptions({followRedirects:true}); + } + } } }, 'And A 302 redirect is received' : { @@ -772,7 +1002,79 @@ vows.describe('OAuth').addBatch({ oa._createClient= op; } } - } + }, + 'and followRedirect is true' : { + 'it should (re)perform the secure request but with the new location' : function(oa) { + var op= oa._createClient; + var psr= oa._performSecureRequest; + var responseCounter = 1; + var callbackCalled = false; + var DummyResponse =function() { + if( responseCounter == 1 ){ + this.statusCode= 302; + this.headers= {location:"http://redirectto.com"}; + responseCounter++; + } + else { + this.statusCode= 200; + } + } + DummyResponse.prototype= events.EventEmitter.prototype; + DummyResponse.prototype.setEncoding= function() {} + + try { + oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) { + return new DummyRequest( new DummyResponse() ); + } + oa._performSecureRequest= function( oauth_token, oauth_token_secret, method, url, extra_params, post_body, post_content_type, callback ) { + if( responseCounter == 1 ) { + assert.equal(url, "http://originalurl.com"); + } + else { + assert.equal(url, "http://redirectto.com"); + } + return psr.call(oa, oauth_token, oauth_token_secret, method, url, extra_params, post_body, post_content_type, callback ) + } + + oa._performSecureRequest("token", "token_secret", 'POST', 'http://originalurl.com', {"scope": "foobar,1,2"}, null, null, function() { + // callback + assert.equal(responseCounter, 2); + callbackCalled= true; + }); + assert.equal(callbackCalled, true) + } + finally { + oa._createClient= op; + oa._performSecureRequest= psr; + } + } + }, + 'and followRedirect is false' : { + 'it should not perform the secure request with the new location' : function(oa) { + var op= oa._createClient; + oa.setClientOptions({ followRedirects: false }); + var DummyResponse =function() { + this.statusCode= 302; + this.headers= {location:"http://redirectto.com"}; + } + DummyResponse.prototype= events.EventEmitter.prototype; + DummyResponse.prototype.setEncoding= function() {} + + try { + oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) { + return new DummyRequest( new DummyResponse() ); + } + oa._performSecureRequest("token", "token_secret", 'POST', 'http://originalurl.com', {"scope": "foobar,1,2"}, null, null, function(res, data, response) { + // callback + assert.equal(res.statusCode, 302); + }); + } + finally { + oa._createClient= op; + oa.setClientOptions({followRedirects:true}); + } + } + } } } } diff --git a/node_modules/twitter/node_modules/oauth/tests/oauth2.js b/node_modules/twitter/node_modules/oauth/tests/oauth2.js index efe8224..ab9bb96 100644 --- a/node_modules/twitter/node_modules/oauth/tests/oauth2.js +++ b/node_modules/twitter/node_modules/oauth/tests/oauth2.js @@ -1,10 +1,13 @@ var vows = require('vows'), assert = require('assert'), - OAuth2= require('../lib/oauth2').OAuth2; + https = require('https'), + OAuth2= require('../lib/oauth2').OAuth2, + url = require('url'); vows.describe('OAuth2').addBatch({ - 'When handling the access token response': { - topic: new OAuth2(), + 'Given an OAuth2 instance with clientId and clientSecret, ': { + topic: new OAuth2("clientId", "clientSecret"), + 'When handling the access token response': { 'we should correctly extract the token if received as form-data': function (oa) { oa._request= function( method, url, fo, bar, bleh, callback) { callback(null, "access_token=access&refresh_token=refresh"); @@ -14,6 +17,27 @@ vows.describe('OAuth2').addBatch({ assert.equal( refresh_token, "refresh"); }); }, + 'we should not include access token in both querystring and headers (favours headers if specified)': function (oa) { + oa._request = new OAuth2("clientId", "clientSecret")._request.bind(oa); + oa._executeRequest= function( http_library, options, post_body, callback) { + callback(null, url.parse(options.path, true).query, options.headers); + }; + + oa._request("GET", "http://foo/", {"Authorization":"Bearer BadNews"}, null, "accessx", function(error, query, headers) { + assert.ok( !('access_token' in query), "access_token also in query"); + assert.ok( 'Authorization' in headers, "Authorization not in headers"); + }); + }, + 'we should include access token in the querystring if no Authorization header present to override it': function (oa) { + oa._request = new OAuth2("clientId", "clientSecret")._request.bind(oa); + oa._executeRequest= function( http_library, options, post_body, callback) { + callback(null, url.parse(options.path, true).query, options.headers); + }; + oa._request("GET", "http://foo/", {}, null, "access", function(error, query, headers) { + assert.ok( 'access_token' in query, "access_token not present in query"); + assert.ok( !('Authorization' in headers), "Authorization in headers"); + }); + }, 'we should correctly extract the token if received as a JSON literal': function (oa) { oa._request= function(method, url, headers, post_body, access_token, callback) { callback(null, '{"access_token":"access","refresh_token":"refresh"}'); @@ -22,6 +46,215 @@ vows.describe('OAuth2').addBatch({ assert.equal( access_token, "access"); assert.equal( refresh_token, "refresh"); }); + }, + 'we should return the received data to the calling method': function (oa) { + oa._request= function(method, url, headers, post_body, access_token, callback) { + callback(null, '{"access_token":"access","refresh_token":"refresh","extra_1":1, "extra_2":"foo"}'); + }; + oa.getOAuthAccessToken("", {}, function(error, access_token, refresh_token, results) { + assert.equal( access_token, "access"); + assert.equal( refresh_token, "refresh"); + assert.isNotNull( results ); + assert.equal( results.extra_1, 1); + assert.equal( results.extra_2, "foo"); + }); + } + }, + 'When no grant_type parameter is specified': { + 'we should pass the value of the code argument as the code parameter': function(oa) { + oa._request= function(method, url, headers, post_body, access_token, callback) { + assert.isTrue( post_body.indexOf("code=xsds23") != -1 ); + }; + oa.getOAuthAccessToken("xsds23", {} ); + } + }, + 'When an invalid grant_type parameter is specified': { + 'we should pass the value of the code argument as the code parameter': function(oa) { + oa._request= function(method, url, headers, post_body, access_token, callback) { + assert.isTrue( post_body.indexOf("code=xsds23") != -1 ); + }; + oa.getOAuthAccessToken("xsds23", {grant_type:"refresh_toucan"} ); + } + }, + 'When a grant_type parameter of value "refresh_token" is specified': { + 'we should pass the value of the code argument as the refresh_token parameter, should pass a grant_type parameter, but shouldn\'t pass a code parameter' : function(oa) { + oa._request= function(method, url, headers, post_body, access_token, callback) { + assert.isTrue( post_body.indexOf("refresh_token=sdsds2") != -1 ); + assert.isTrue( post_body.indexOf("grant_type=refresh_token") != -1 ); + assert.isTrue( post_body.indexOf("code=") == -1 ); + }; + oa.getOAuthAccessToken("sdsds2", {grant_type:"refresh_token"} ); + } + }, + 'When we use the authorization header': { + 'and call get with the default authorization method': { + 'we should pass the authorization header with Bearer method and value of the access_token, _request should be passed a null access_token' : function(oa) { + oa._request= function(method, url, headers, post_body, access_token, callback) { + assert.equal(headers["Authorization"], "Bearer abcd5"); + assert.isNull( access_token ); + }; + oa.useAuthorizationHeaderforGET(true); + oa.get("", "abcd5"); + } + }, + 'and call get with the authorization method set to Basic': { + 'we should pass the authorization header with Basic method and value of the access_token, _request should be passed a null access_token' : function(oa) { + oa._request= function(method, url, headers, post_body, access_token, callback) { + assert.equal(headers["Authorization"], "Basic cdg2"); + assert.isNull( access_token ); + }; + oa.useAuthorizationHeaderforGET(true); + oa.setAuthMethod("Basic"); + oa.get("", "cdg2"); + } + } + }, + 'When we do not use the authorization header': { + 'and call get': { + 'we should pass NOT provide an authorization header and the access_token should be being passed to _request' : function(oa) { + oa._request= function(method, url, headers, post_body, access_token, callback) { + assert.isUndefined(headers["Authorization"]); + assert.equal( access_token, "abcd5" ); + }; + oa.useAuthorizationHeaderforGET(false); + oa.get("", "abcd5"); + } + } + } + }, + 'Given an OAuth2 instance with clientId, clientSecret and customHeaders': { + topic: new OAuth2("clientId", "clientSecret", undefined, undefined, undefined, + { 'SomeHeader': '123' }), + 'When GETing': { + 'we should see the custom headers mixed into headers property in options passed to http-library' : function(oa) { + oa._executeRequest= function( http_library, options, callback ) { + assert.equal(options.headers["SomeHeader"], "123"); + }; + oa.get("", {}); + }, + } + }, + 'Given an OAuth2 instance with a clientId and clientSecret': { + topic: new OAuth2("clientId", "clientSecret"), + 'When POSTing': { + 'we should see a given string being sent to the request' : function(oa) { + var bodyWritten= false; + oa._chooseHttpLibrary= function() { + return { + request: function(options) { + assert.equal(options.headers["Content-Type"], "text/plain"); + assert.equal(options.headers["Content-Length"], 26); + assert.equal(options.method, "POST"); + return { + end: function() {}, + on: function() {}, + write: function(body) { + bodyWritten= true; + assert.isNotNull(body); + assert.equal(body, "THIS_IS_A_POST_BODY_STRING") + } + } + } + }; + } + oa._request("POST", "", {"Content-Type":"text/plain"}, "THIS_IS_A_POST_BODY_STRING"); + assert.ok( bodyWritten ); + }, + 'we should see a given buffer being sent to the request' : function(oa) { + var bodyWritten= false; + oa._chooseHttpLibrary= function() { + return { + request: function(options) { + assert.equal(options.headers["Content-Type"], "application/octet-stream"); + assert.equal(options.headers["Content-Length"], 4); + assert.equal(options.method, "POST"); + return { + end: function() {}, + on: function() {}, + write: function(body) { + bodyWritten= true; + assert.isNotNull(body); + assert.equal(4, body.length) + } + } + } + }; + } + oa._request("POST", "", {"Content-Type":"application/octet-stream"}, new Buffer([1,2,3,4])); + assert.ok( bodyWritten ); + } + }, + 'When PUTing': { + 'we should see a given string being sent to the request' : function(oa) { + var bodyWritten= false; + oa._chooseHttpLibrary= function() { + return { + request: function(options) { + assert.equal(options.headers["Content-Type"], "text/plain"); + assert.equal(options.headers["Content-Length"], 25); + assert.equal(options.method, "PUT"); + return { + end: function() {}, + on: function() {}, + write: function(body) { + bodyWritten= true; + assert.isNotNull(body); + assert.equal(body, "THIS_IS_A_PUT_BODY_STRING") + } + } + } + }; + } + oa._request("PUT", "", {"Content-Type":"text/plain"}, "THIS_IS_A_PUT_BODY_STRING"); + assert.ok( bodyWritten ); + }, + 'we should see a given buffer being sent to the request' : function(oa) { + var bodyWritten= false; + oa._chooseHttpLibrary= function() { + return { + request: function(options) { + assert.equal(options.headers["Content-Type"], "application/octet-stream"); + assert.equal(options.headers["Content-Length"], 4); + assert.equal(options.method, "PUT"); + return { + end: function() {}, + on: function() {}, + write: function(body) { + bodyWritten= true; + assert.isNotNull(body); + assert.equal(4, body.length) + } + } + } + }; + } + oa._request("PUT", "", {"Content-Type":"application/octet-stream"}, new Buffer([1,2,3,4])); + assert.ok( bodyWritten ); + } + } + }, + 'When the user passes in the User-Agent in customHeaders': { + topic: new OAuth2("clientId", "clientSecret", undefined, undefined, undefined, + { 'User-Agent': '123Agent' }), + 'When calling get': { + 'we should see the User-Agent mixed into headers property in options passed to http-library' : function(oa) { + oa._executeRequest= function( http_library, options, callback ) { + assert.equal(options.headers["User-Agent"], "123Agent"); + }; + oa.get("", {}); + } + } + }, + 'When the user does not pass in a User-Agent in customHeaders': { + topic: new OAuth2("clientId", "clientSecret", undefined, undefined, undefined, + undefined), + 'When calling get': { + 'we should see the default User-Agent mixed into headers property in options passed to http-library' : function(oa) { + oa._executeRequest= function( http_library, options, callback ) { + assert.equal(options.headers["User-Agent"], "Node-oauth"); + }; + oa.get("", {}); } + } } -}).export(module); \ No newline at end of file +}).export(module); diff --git a/node_modules/twitter/package.json b/node_modules/twitter/package.json index f516864..992f1a3 100644 --- a/node_modules/twitter/package.json +++ b/node_modules/twitter/package.json @@ -1,21 +1,64 @@ -{ "name": "twitter" -, "version": "v0.1.17" -, "description": "Asynchronous Twitter REST/stream/search client API for node.js." -, "keywords": ["twitter","streaming","oauth"] -, "homepage": "https://github.com/jdub/node-twitter" -, "author": "jdub" -, "licenses": - [ { "type": "MIT" - , "url": "http://github.com/jdub/node-twitter/raw/master/LICENSE" - } ] -, "repository": - { "type": "git" - , "url": "http://github.com/jdub/node-twitter.git" - } -, "dependencies": - { "oauth": ">=0.8.4" - , "cookie": ">=0.1.4" - } -, "engines": ["node >=0.2.0"] -, "main": "./lib/twitter" +{ + "name": "twitter", + "version": "0.1.19", + "description": "Twitter API client library for node.js", + "keywords": [ + "twitter", + "streaming", + "oauth" + ], + "homepage": "https://github.com/desmondmorris/node-twitter", + "author": { + "name": "jdub" + }, + "licenses": [ + { + "type": "MIT", + "url": "http://github.com/desmondmorris/node-twitter/raw/master/LICENSE" + } + ], + "repository": { + "type": "git", + "url": "http://github.com/desmondmorris/node-twitter.git" + }, + "dependencies": { + "oauth": ">=0.8.4", + "cookies": ">=0.1.6", + "keygrip": ">=0.1.7" + }, + "devDependencies": { + "grunt": "~0.4.1", + "grunt-release": "~0.6.0" + }, + "engines": [ + "node >=0.2.0" + ], + "main": "./lib/twitter", + "bugs": { + "url": "https://github.com/desmondmorris/node-twitter/issues" + }, + "_id": "twitter@0.1.19", + "dist": { + "shasum": "97e306daa6a23371a7198eea2f8a9bab22e96b54", + "tarball": "http://registry.npmjs.org/twitter/-/twitter-0.1.19.tgz" + }, + "_from": "twitter@~0.1.19", + "_npmVersion": "1.3.8", + "_npmUser": { + "name": "desmondmorris", + "email": "hi@desmondmorris.com" + }, + "maintainers": [ + { + "name": "jdub", + "email": "jdub@bethesignal.org" + }, + { + "name": "desmondmorris", + "email": "hi@desmondmorris.com" + } + ], + "directories": {}, + "_shasum": "97e306daa6a23371a7198eea2f8a9bab22e96b54", + "_resolved": "https://registry.npmjs.org/twitter/-/twitter-0.1.19.tgz" } diff --git a/package.json b/package.json index 513467e..ed02666 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "repository": "https://github.com/oftn/oftn-bot", "dependencies": { - "twitter": "~0.1.17" + "twitter": "~0.1.19" } }