index.js 3.8 KB

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