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