77// pseudo constants
88//
99var TWITTER_API_TIMEOUT = 10000 ,
10- TWITTER_API_USERAGENT = 'Node/' + process . version . substr ( 1 ) ,
10+ TWITTER_API_USERAGENT = 'Node/' + process . version . substr ( 1 ) + '; https://github.com/timwhitlock/node-twitter-api' ,
1111 TWITTER_API_BASE = 'https://api.twitter.com/1.1' ,
1212 TWITTER_STREAM_BASE = 'https://stream.twitter.com/1.1' ,
1313 TWITTER_OAUTH_REQUEST_TOKEN_URL = 'https://twitter.com/oauth/request_token' ,
@@ -18,7 +18,31 @@ var TWITTER_API_TIMEOUT = 10000,
1818 TWITTER_OAUTH2_INVALIDATE_URL = 'https://api.twitter.com/oauth2/invalidate_token' ;
1919
2020
21+ /**
22+ * OAuth safe encodeURIComponent of string
23+ * handles ignored characters that OAuth expects encoded "! * ' ( )"
24+ */
25+ function uriEncodeString ( text ) {
26+ return encodeURIComponent ( text ) . replace ( / [ \! \* \' \( \) ] / g, function ( chr ) {
27+ chr = chr . charCodeAt ( 0 ) . toString ( 16 ) ;
28+ while ( chr . length < 2 ) {
29+ chr = '0' + hex ;
30+ }
31+ return '%' + chr ;
32+ } )
33+ }
34+
2135
36+ /**
37+ * OAuth safe encodeURIComponent of params object
38+ */
39+ function uriEncodeParams ( obj ) {
40+ var pairs = [ ] , key ;
41+ for ( key in obj ) {
42+ pairs . push ( uriEncodeString ( key ) + '=' + uriEncodeString ( obj [ key ] ) ) ;
43+ }
44+ return pairs . join ( '&' ) ;
45+ }
2246
2347
2448/**
@@ -87,7 +111,7 @@ OAuthParams.prototype.normalize = function(){
87111}
88112
89113OAuthParams . prototype . serialize = function ( ) {
90- return require ( 'querystring' ) . stringify ( this . args ) ;
114+ return uriEncodeParams ( this . args ) ;
91115}
92116
93117OAuthParams . prototype . sign = function ( requestMethod , requestUri ) {
@@ -99,8 +123,8 @@ OAuthParams.prototype.sign = function( requestMethod, requestUri ){
99123 delete this . args . oauth_signature ;
100124 // normalize, build and sign
101125 this . normalize ( ) ;
102- var str = requestMethod . toUpperCase ( ) + '&' + encodeURIComponent ( requestUri ) + '&' + encodeURIComponent ( this . serialize ( ) ) ,
103- key = encodeURIComponent ( this . consumer_secret ) + '&' + encodeURIComponent ( this . token_secret ) ,
126+ var str = requestMethod . toUpperCase ( ) + '&' + uriEncodeString ( requestUri ) + '&' + uriEncodeString ( this . serialize ( ) ) ,
127+ key = uriEncodeString ( this . consumer_secret ) + '&' + uriEncodeString ( this . token_secret ) ,
104128 hash = require ( 'crypto' ) . createHmac ( 'sha1' , key ) . update ( str ) ;
105129 this . args . oauth_signature = hash . digest ( 'base64' ) ;
106130 return this ;
@@ -309,6 +333,7 @@ TwitterClient.prototype._call = function( requestMethod, requestUri, requestArgs
309333 authHeader = params . getHeader ( ) ;
310334 }
311335 var query = params . serialize ( ) ;
336+
312337 // build http request starting with parsed endpoint
313338 var http = require ( 'url' ) . parse ( requestUri ) ;
314339 http . headers = {
0 commit comments