index.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. var crypto = require('crypto')
  2. , qs = require('querystring')
  3. ;
  4. function sha1 (key, body) {
  5. return crypto.createHmac('sha1', key).update(body).digest('base64')
  6. }
  7. function rsa (key, body) {
  8. return crypto.createSign("RSA-SHA1").update(body).sign(key, 'base64');
  9. }
  10. function rfc3986 (str) {
  11. return encodeURIComponent(str)
  12. .replace(/!/g,'%21')
  13. .replace(/\*/g,'%2A')
  14. .replace(/\(/g,'%28')
  15. .replace(/\)/g,'%29')
  16. .replace(/'/g,'%27')
  17. ;
  18. }
  19. // Maps object to bi-dimensional array
  20. // Converts { foo: 'A', bar: [ 'b', 'B' ]} to
  21. // [ ['foo', 'A'], ['bar', 'b'], ['bar', 'B'] ]
  22. function map (obj) {
  23. var key, val, arr = []
  24. for (key in obj) {
  25. val = obj[key]
  26. if (Array.isArray(val))
  27. for (var i = 0; i < val.length; i++)
  28. arr.push([key, val[i]])
  29. else if (typeof val === "object")
  30. for (var prop in val)
  31. arr.push([key + '[' + prop + ']', val[prop]]);
  32. else
  33. arr.push([key, val])
  34. }
  35. return arr
  36. }
  37. // Compare function for sort
  38. function compare (a, b) {
  39. return a > b ? 1 : a < b ? -1 : 0
  40. }
  41. function generateBase (httpMethod, base_uri, params) {
  42. // adapted from https://dev.twitter.com/docs/auth/oauth and
  43. // https://dev.twitter.com/docs/auth/creating-signature
  44. // Parameter normalization
  45. // http://tools.ietf.org/html/rfc5849#section-3.4.1.3.2
  46. var normalized = map(params)
  47. // 1. First, the name and value of each parameter are encoded
  48. .map(function (p) {
  49. return [ rfc3986(p[0]), rfc3986(p[1] || '') ]
  50. })
  51. // 2. The parameters are sorted by name, using ascending byte value
  52. // ordering. If two or more parameters share the same name, they
  53. // are sorted by their value.
  54. .sort(function (a, b) {
  55. return compare(a[0], b[0]) || compare(a[1], b[1])
  56. })
  57. // 3. The name of each parameter is concatenated to its corresponding
  58. // value using an "=" character (ASCII code 61) as a separator, even
  59. // if the value is empty.
  60. .map(function (p) { return p.join('=') })
  61. // 4. The sorted name/value pairs are concatenated together into a
  62. // single string by using an "&" character (ASCII code 38) as
  63. // separator.
  64. .join('&')
  65. var base = [
  66. rfc3986(httpMethod ? httpMethod.toUpperCase() : 'GET'),
  67. rfc3986(base_uri),
  68. rfc3986(normalized)
  69. ].join('&')
  70. return base
  71. }
  72. function hmacsign (httpMethod, base_uri, params, consumer_secret, token_secret) {
  73. var base = generateBase(httpMethod, base_uri, params)
  74. var key = [
  75. consumer_secret || '',
  76. token_secret || ''
  77. ].map(rfc3986).join('&')
  78. return sha1(key, base)
  79. }
  80. function rsasign (httpMethod, base_uri, params, private_key, token_secret) {
  81. var base = generateBase(httpMethod, base_uri, params)
  82. var key = private_key || ''
  83. return rsa(key, base)
  84. }
  85. function plaintext (consumer_secret, token_secret) {
  86. var key = [
  87. consumer_secret || '',
  88. token_secret || ''
  89. ].map(rfc3986).join('&')
  90. return key
  91. }
  92. function sign (signMethod, httpMethod, base_uri, params, consumer_secret, token_secret) {
  93. var method
  94. var skipArgs = 1
  95. switch (signMethod) {
  96. case 'RSA-SHA1':
  97. method = rsasign
  98. break
  99. case 'HMAC-SHA1':
  100. method = hmacsign
  101. break
  102. case 'PLAINTEXT':
  103. method = plaintext
  104. skipArgs = 4
  105. break
  106. default:
  107. throw new Error("Signature method not supported: " + signMethod)
  108. }
  109. return method.apply(null, [].slice.call(arguments, skipArgs))
  110. }
  111. exports.hmacsign = hmacsign
  112. exports.rsasign = rsasign
  113. exports.plaintext = plaintext
  114. exports.sign = sign
  115. exports.rfc3986 = rfc3986
  116. exports.generateBase = generateBase