You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					146 lines
				
				3.8 KiB
			
		
		
			
		
	
	
					146 lines
				
				3.8 KiB
			| 
											3 years ago
										 | var crypto = require('crypto') | ||
|  | 
 | ||
|  | function sha (key, body, algorithm) { | ||
|  |   return crypto.createHmac(algorithm, key).update(body).digest('base64') | ||
|  | } | ||
|  | 
 | ||
|  | function rsa (key, body) { | ||
|  |   return crypto.createSign('RSA-SHA1').update(body).sign(key, 'base64') | ||
|  | } | ||
|  | 
 | ||
|  | function rfc3986 (str) { | ||
|  |   return encodeURIComponent(str) | ||
|  |     .replace(/!/g,'%21') | ||
|  |     .replace(/\*/g,'%2A') | ||
|  |     .replace(/\(/g,'%28') | ||
|  |     .replace(/\)/g,'%29') | ||
|  |     .replace(/'/g,'%27') | ||
|  | } | ||
|  | 
 | ||
|  | // Maps object to bi-dimensional array
 | ||
|  | // Converts { foo: 'A', bar: [ 'b', 'B' ]} to
 | ||
|  | // [ ['foo', 'A'], ['bar', 'b'], ['bar', 'B'] ]
 | ||
|  | function map (obj) { | ||
|  |   var key, val, arr = [] | ||
|  |   for (key in obj) { | ||
|  |     val = obj[key] | ||
|  |     if (Array.isArray(val)) | ||
|  |       for (var i = 0; i < val.length; i++) | ||
|  |         arr.push([key, val[i]]) | ||
|  |     else if (typeof val === 'object') | ||
|  |       for (var prop in val) | ||
|  |         arr.push([key + '[' + prop + ']', val[prop]]) | ||
|  |     else | ||
|  |       arr.push([key, val]) | ||
|  |   } | ||
|  |   return arr | ||
|  | } | ||
|  | 
 | ||
|  | // Compare function for sort
 | ||
|  | function compare (a, b) { | ||
|  |   return a > b ? 1 : a < b ? -1 : 0 | ||
|  | } | ||
|  | 
 | ||
|  | function generateBase (httpMethod, base_uri, params) { | ||
|  |   // adapted from https://dev.twitter.com/docs/auth/oauth and 
 | ||
|  |   // https://dev.twitter.com/docs/auth/creating-signature
 | ||
|  | 
 | ||
|  |   // Parameter normalization
 | ||
|  |   // http://tools.ietf.org/html/rfc5849#section-3.4.1.3.2
 | ||
|  |   var normalized = map(params) | ||
|  |   // 1.  First, the name and value of each parameter are encoded
 | ||
|  |   .map(function (p) { | ||
|  |     return [ rfc3986(p[0]), rfc3986(p[1] || '') ] | ||
|  |   }) | ||
|  |   // 2.  The parameters are sorted by name, using ascending byte value
 | ||
|  |   //     ordering.  If two or more parameters share the same name, they
 | ||
|  |   //     are sorted by their value.
 | ||
|  |   .sort(function (a, b) { | ||
|  |     return compare(a[0], b[0]) || compare(a[1], b[1]) | ||
|  |   }) | ||
|  |   // 3.  The name of each parameter is concatenated to its corresponding
 | ||
|  |   //     value using an "=" character (ASCII code 61) as a separator, even
 | ||
|  |   //     if the value is empty.
 | ||
|  |   .map(function (p) { return p.join('=') }) | ||
|  |    // 4.  The sorted name/value pairs are concatenated together into a
 | ||
|  |    //     single string by using an "&" character (ASCII code 38) as
 | ||
|  |    //     separator.
 | ||
|  |   .join('&') | ||
|  | 
 | ||
|  |   var base = [ | ||
|  |     rfc3986(httpMethod ? httpMethod.toUpperCase() : 'GET'), | ||
|  |     rfc3986(base_uri), | ||
|  |     rfc3986(normalized) | ||
|  |   ].join('&') | ||
|  | 
 | ||
|  |   return base | ||
|  | } | ||
|  | 
 | ||
|  | function hmacsign (httpMethod, base_uri, params, consumer_secret, token_secret) { | ||
|  |   var base = generateBase(httpMethod, base_uri, params) | ||
|  |   var key = [ | ||
|  |     consumer_secret || '', | ||
|  |     token_secret || '' | ||
|  |   ].map(rfc3986).join('&') | ||
|  | 
 | ||
|  |   return sha(key, base, 'sha1') | ||
|  | } | ||
|  | 
 | ||
|  | function hmacsign256 (httpMethod, base_uri, params, consumer_secret, token_secret) { | ||
|  |   var base = generateBase(httpMethod, base_uri, params) | ||
|  |   var key = [ | ||
|  |     consumer_secret || '', | ||
|  |     token_secret || '' | ||
|  |   ].map(rfc3986).join('&') | ||
|  | 
 | ||
|  |   return sha(key, base, 'sha256') | ||
|  | } | ||
|  | 
 | ||
|  | function rsasign (httpMethod, base_uri, params, private_key, token_secret) { | ||
|  |   var base = generateBase(httpMethod, base_uri, params) | ||
|  |   var key = private_key || '' | ||
|  | 
 | ||
|  |   return rsa(key, base) | ||
|  | } | ||
|  | 
 | ||
|  | function plaintext (consumer_secret, token_secret) { | ||
|  |   var key = [ | ||
|  |     consumer_secret || '', | ||
|  |     token_secret || '' | ||
|  |   ].map(rfc3986).join('&') | ||
|  | 
 | ||
|  |   return key | ||
|  | } | ||
|  | 
 | ||
|  | function sign (signMethod, httpMethod, base_uri, params, consumer_secret, token_secret) { | ||
|  |   var method | ||
|  |   var skipArgs = 1 | ||
|  | 
 | ||
|  |   switch (signMethod) { | ||
|  |     case 'RSA-SHA1': | ||
|  |       method = rsasign | ||
|  |       break | ||
|  |     case 'HMAC-SHA1': | ||
|  |       method = hmacsign | ||
|  |       break | ||
|  |     case 'HMAC-SHA256': | ||
|  |       method = hmacsign256 | ||
|  |       break | ||
|  |     case 'PLAINTEXT': | ||
|  |       method = plaintext | ||
|  |       skipArgs = 4 | ||
|  |       break | ||
|  |     default: | ||
|  |      throw new Error('Signature method not supported: ' + signMethod) | ||
|  |   } | ||
|  | 
 | ||
|  |   return method.apply(null, [].slice.call(arguments, skipArgs)) | ||
|  | } | ||
|  | 
 | ||
|  | exports.hmacsign = hmacsign | ||
|  | exports.hmacsign256 = hmacsign256 | ||
|  | exports.rsasign = rsasign | ||
|  | exports.plaintext = plaintext | ||
|  | exports.sign = sign | ||
|  | exports.rfc3986 = rfc3986 | ||
|  | exports.generateBase = generateBase |