UNPKG

3.93 kBJavaScriptView Raw
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
\No newline at end of file