Initial commit
[yaffs-website] / node_modules / aws-sign2 / index.js
1
2 /*!
3  *  Copyright 2010 LearnBoost <dev@learnboost.com>
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 /**
19  * Module dependencies.
20  */
21
22 var crypto = require('crypto')
23   , parse = require('url').parse
24   ;
25
26 /**
27  * Valid keys.
28  */
29
30 var keys = 
31   [ 'acl'
32   , 'location'
33   , 'logging'
34   , 'notification'
35   , 'partNumber'
36   , 'policy'
37   , 'requestPayment'
38   , 'torrent'
39   , 'uploadId'
40   , 'uploads'
41   , 'versionId'
42   , 'versioning'
43   , 'versions'
44   , 'website'
45   ]
46
47 /**
48  * Return an "Authorization" header value with the given `options`
49  * in the form of "AWS <key>:<signature>"
50  *
51  * @param {Object} options
52  * @return {String}
53  * @api private
54  */
55
56 function authorization (options) {
57   return 'AWS ' + options.key + ':' + sign(options)
58 }
59
60 module.exports = authorization
61 module.exports.authorization = authorization
62
63 /**
64  * Simple HMAC-SHA1 Wrapper
65  *
66  * @param {Object} options
67  * @return {String}
68  * @api private
69  */ 
70
71 function hmacSha1 (options) {
72   return crypto.createHmac('sha1', options.secret).update(options.message).digest('base64')
73 }
74
75 module.exports.hmacSha1 = hmacSha1
76
77 /**
78  * Create a base64 sha1 HMAC for `options`. 
79  * 
80  * @param {Object} options
81  * @return {String}
82  * @api private
83  */
84
85 function sign (options) {
86   options.message = stringToSign(options)
87   return hmacSha1(options)
88 }
89 module.exports.sign = sign
90
91 /**
92  * Create a base64 sha1 HMAC for `options`. 
93  *
94  * Specifically to be used with S3 presigned URLs
95  * 
96  * @param {Object} options
97  * @return {String}
98  * @api private
99  */
100
101 function signQuery (options) {
102   options.message = queryStringToSign(options)
103   return hmacSha1(options)
104 }
105 module.exports.signQuery= signQuery
106
107 /**
108  * Return a string for sign() with the given `options`.
109  *
110  * Spec:
111  * 
112  *    <verb>\n
113  *    <md5>\n
114  *    <content-type>\n
115  *    <date>\n
116  *    [headers\n]
117  *    <resource>
118  *
119  * @param {Object} options
120  * @return {String}
121  * @api private
122  */
123
124 function stringToSign (options) {
125   var headers = options.amazonHeaders || ''
126   if (headers) headers += '\n'
127   var r = 
128     [ options.verb
129     , options.md5
130     , options.contentType
131     , options.date ? options.date.toUTCString() : ''
132     , headers + options.resource
133     ]
134   return r.join('\n')
135 }
136 module.exports.queryStringToSign = stringToSign
137
138 /**
139  * Return a string for sign() with the given `options`, but is meant exclusively
140  * for S3 presigned URLs
141  *
142  * Spec:
143  * 
144  *    <date>\n
145  *    <resource>
146  *
147  * @param {Object} options
148  * @return {String}
149  * @api private
150  */
151
152 function queryStringToSign (options){
153   return 'GET\n\n\n' + options.date + '\n' + options.resource
154 }
155 module.exports.queryStringToSign = queryStringToSign
156
157 /**
158  * Perform the following:
159  *
160  *  - ignore non-amazon headers
161  *  - lowercase fields
162  *  - sort lexicographically
163  *  - trim whitespace between ":"
164  *  - join with newline
165  *
166  * @param {Object} headers
167  * @return {String}
168  * @api private
169  */
170
171 function canonicalizeHeaders (headers) {
172   var buf = []
173     , fields = Object.keys(headers)
174     ;
175   for (var i = 0, len = fields.length; i < len; ++i) {
176     var field = fields[i]
177       , val = headers[field]
178       , field = field.toLowerCase()
179       ;
180     if (0 !== field.indexOf('x-amz')) continue
181     buf.push(field + ':' + val)
182   }
183   return buf.sort().join('\n')
184 }
185 module.exports.canonicalizeHeaders = canonicalizeHeaders
186
187 /**
188  * Perform the following:
189  *
190  *  - ignore non sub-resources
191  *  - sort lexicographically
192  *
193  * @param {String} resource
194  * @return {String}
195  * @api private
196  */
197
198 function canonicalizeResource (resource) {
199   var url = parse(resource, true)
200     , path = url.pathname
201     , buf = []
202     ;
203
204   Object.keys(url.query).forEach(function(key){
205     if (!~keys.indexOf(key)) return
206     var val = '' == url.query[key] ? '' : '=' + encodeURIComponent(url.query[key])
207     buf.push(key + val)
208   })
209
210   return path + (buf.length ? '?' + buf.sort().join('&') : '')
211 }
212 module.exports.canonicalizeResource = canonicalizeResource